The Battle for Wesnoth  1.19.1+dev
manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
3  by Yurii Chernyi <terraninfo@terraninfo.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  * Managing the AI lifecycle and interface for the rest of Wesnoth
18  * @file
19  */
20 
21 #include "ai/manager.hpp"
22 
23 #include "config.hpp" // for config, etc
24 #include "game_events/pump.hpp"
25 #include "log.hpp"
26 #include "map/location.hpp" // for map_location
27 #include "resources.hpp"
29 #include "tod_manager.hpp"
30 
31 #include "ai/composite/ai.hpp" // for ai_composite
32 #include "ai/composite/component.hpp" // for component_manager
33 #include "ai/composite/engine.hpp" // for engine
35 #include "ai/configuration.hpp" // for configuration
36 #include "ai/contexts.hpp" // for readonly_context, etc
37 #include "ai/default/contexts.hpp" // for default_ai_context, etc
38 #include "ai/game_info.hpp" // for side_number, engine_ptr, etc
39 #include "game_config.hpp" // for debug
41 #include "ai/registry.hpp" // for init
42 #include "ai/lua/engine_lua.hpp"
43 
44 #include <algorithm> // for min
45 #include <cassert> // for assert
46 #include <iterator> // for reverse_iterator, etc
47 #include <map> // for _Rb_tree_iterator, etc
48 #include <set> // for set
49 #include <stack> // for stack
50 #include <utility> // for pair, make_pair
51 #include <vector> // for vector, allocator, etc
52 
53 #include <SDL2/SDL_timer.h>
54 
55 namespace ai {
56 
57 const std::string manager::AI_TYPE_COMPOSITE_AI = "composite_ai";
58 const std::string manager::AI_TYPE_SAMPLE_AI = "sample_ai";
59 const std::string manager::AI_TYPE_IDLE_AI = "idle_ai";
60 const std::string manager::AI_TYPE_FORMULA_AI = "formula_ai";
61 const std::string manager::AI_TYPE_DEFAULT = "default";
62 
63 static lg::log_domain log_ai_manager("ai/manager");
64 #define DBG_AI_MANAGER LOG_STREAM(debug, log_ai_manager)
65 #define LOG_AI_MANAGER LOG_STREAM(info, log_ai_manager)
66 #define ERR_AI_MANAGER LOG_STREAM(err, log_ai_manager)
67 
68 static lg::log_domain log_ai_mod("ai/mod");
69 #define DBG_AI_MOD LOG_STREAM(debug, log_ai_mod)
70 #define LOG_AI_MOD LOG_STREAM(info, log_ai_mod)
71 #define WRN_AI_MOD LOG_STREAM(warn, log_ai_mod)
72 #define ERR_AI_MOD LOG_STREAM(err, log_ai_mod)
73 
74 holder::holder( side_number side, const config &cfg )
75  : ai_(), side_context_(nullptr), readonly_context_(nullptr), readwrite_context_(nullptr), default_ai_context_(nullptr), side_(side), cfg_(cfg)
76 {
77  DBG_AI_MANAGER << describe_ai() << "Preparing new AI holder";
78 }
79 
81 {
82  if (side_context_ == nullptr) {
83  side_context_.reset(new side_context_impl(side,cfg_));
84  } else {
85  side_context_->set_side(side);
86  }
87  if (readonly_context_ == nullptr){
89  readonly_context_->on_readonly_context_create();
90  }
91  if (readwrite_context_ == nullptr){
93  }
94  if (default_ai_context_ == nullptr){
96  }
97  if (!this->ai_){
99  }
100 
101  if (this->ai_) {
102  ai_->on_create();
103  for (config &mod_ai : cfg_.child_range("modify_ai")) {
104  if (!mod_ai.has_attribute("side")) {
105  mod_ai["side"] = side;
106  }
107  modify_ai(mod_ai);
108  }
109  for(config& micro : cfg_.child_range("micro_ai")) {
110  micro["side"] = side;
111  micro["action"] = "add";
112  micro_ai(micro);
113  }
114  cfg_.clear_children("modify_ai", "micro_ai");
115 
116  std::vector<engine_ptr> engines = ai_->get_engines();
117  for (std::vector<engine_ptr>::iterator it = engines.begin(); it != engines.end(); ++it)
118  {
119  (*it)->set_ai_context(&(ai_->get_ai_context()));
120  }
121 
122  } else {
123  ERR_AI_MANAGER << describe_ai()<<"AI lazy initialization error!";
124  }
125 
126 }
127 
129 {
130  try {
131  if (this->ai_) {
132  LOG_AI_MANAGER << describe_ai() << "Managed AI will be deleted";
133  }
134  } catch (...) {}
135 }
136 
138 {
139  if (!this->ai_) {
140  this->init(this->side_);
141  }
142  assert(this->ai_);
143 
144  return *this->ai_;
145 }
146 
147 void holder::micro_ai(const config& cfg)
148 {
149  if (!this->ai_) {
150  this->init(this->side_);
151  }
152  assert(this->ai_);
153 
154  auto engine = this->ai_->get_engine_by_cfg(config{"engine", "lua"});
155  if(auto lua = std::dynamic_pointer_cast<engine_lua>(engine)) {
156  lua->apply_micro_ai(cfg);
157  }
158 }
159 
160 void holder::modify_ai(const config &cfg)
161 {
162  if (!this->ai_) {
163  // if not initialized, initialize now.
164  get_ai_ref();
165  }
166  const std::string &act = cfg["action"];
167  LOG_AI_MOD << "side "<< side_ << " "<<act<<"_ai_component \""<<cfg["path"]<<"\"";
168  DBG_AI_MOD << std::endl << cfg;
169  DBG_AI_MOD << "side "<< side_ << " before "<<act<<"_ai_component"<<std::endl << to_config();
170  bool res = false;
171  if (act == "add") {
172  res = component_manager::add_component(&*this->ai_,cfg["path"],cfg);
173  } else if (act == "change") {
174  res = component_manager::change_component(&*this->ai_,cfg["path"],cfg);
175  } else if (act == "delete") {
176  res = component_manager::delete_component(&*this->ai_,cfg["path"]);
177  } else {
178  ERR_AI_MOD << "modify_ai tag has invalid 'action' attribute " << act;
179  }
180  DBG_AI_MOD << "side "<< side_ << " after [modify_ai]"<<act<<std::endl << to_config();
181  if (!res) {
182  LOG_AI_MOD << act << "_ai_component failed";
183  } else {
184  LOG_AI_MOD << act << "_ai_component success";
185  }
186 
187 }
188 
189 void holder::append_ai(const config& cfg)
190 {
191  if(!this->ai_) {
192  get_ai_ref();
193  }
194  for(const config& aspect : cfg.child_range("aspect")) {
195  const std::string& id = aspect["id"];
196  for(const config& facet : aspect.child_range("facet")) {
197  ai_->add_facet(id, facet);
198  }
199  }
200  for(const config& goal : cfg.child_range("goal")) {
201  ai_->add_goal(goal);
202  }
203  for(const config& stage : cfg.child_range("stage")) {
204  if(stage["name"] != "empty") {
205  ai_->add_stage(stage);
206  }
207  }
208  for(config mod : cfg.child_range("modify_ai")) {
209  if (!mod.has_attribute("side")) {
210  mod["side"] = side_context_->get_side();
211  }
212  modify_ai(mod);
213  }
214  for(config micro : cfg.child_range("micro_ai")) {
215  micro["side"] = side_context_->get_side();
216  micro["action"] = "add";
217  micro_ai(micro);
218  }
219 }
220 
222 {
223  if (!this->ai_) {
224  return cfg_;
225  } else {
226  config cfg = ai_->to_config();
227  if (this->side_context_!=nullptr) {
228  cfg.merge_with(this->side_context_->to_side_context_config());
229  }
230  if (this->readonly_context_!=nullptr) {
231  cfg.merge_with(this->readonly_context_->to_readonly_context_config());
232  }
233  if (this->readwrite_context_!=nullptr) {
234  cfg.merge_with(this->readwrite_context_->to_readwrite_context_config());
235  }
236  if (this->default_ai_context_!=nullptr) {
237  cfg.merge_with(this->default_ai_context_->to_default_ai_context_config());
238  }
239 
240  return cfg;
241  }
242 }
243 
244 const std::string holder::describe_ai()
245 {
246  std::string sidestr = std::to_string(this->side_);
247 
248  if (this->ai_!=nullptr) {
249  return this->ai_->describe_self()+std::string(" for side ")+sidestr+std::string(" : ");
250  } else {
251  return std::string("not initialized ai with id=[")+cfg_["id"]+std::string("] for side ")+sidestr+std::string(" : ");
252  }
253 }
254 
255 const std::string holder::get_ai_overview()
256 {
257  if (!this->ai_) {
258  get_ai_ref();
259  }
260  // These assignments are necessary because the code will otherwise not compile on some platforms with an lvalue/rvalue mismatch error
261  auto lik = this->ai_->get_leader_ignores_keep();
262  auto pl = this->ai_->get_passive_leader();
263  auto plsk = this->ai_->get_passive_leader_shares_keep();
264  // In order to display booleans as yes/no rather than 1/0 or true/false
265  config cfg;
266  cfg["allow_ally_villages"] = this->ai_->get_allow_ally_villages();
267  cfg["simple_targeting"] = this->ai_->get_simple_targeting();
268  cfg["support_villages"] = this->ai_->get_support_villages();
269  std::stringstream s;
270  s << "advancements: " << this->ai_->get_advancements().get_value() << std::endl;
271  s << "aggression: " << this->ai_->get_aggression() << std::endl;
272  s << "allow_ally_villages: " << cfg["allow_ally_villages"] << std::endl;
273  s << "caution: " << this->ai_->get_caution() << std::endl;
274  s << "grouping: " << this->ai_->get_grouping() << std::endl;
275  s << "leader_aggression: " << this->ai_->get_leader_aggression() << std::endl;
276  s << "leader_ignores_keep: " << utils::visit(leader_aspects_visitor(), lik) << std::endl;
277  s << "leader_value: " << this->ai_->get_leader_value() << std::endl;
278  s << "passive_leader: " << utils::visit(leader_aspects_visitor(), pl) << std::endl;
279  s << "passive_leader_shares_keep: " << utils::visit(leader_aspects_visitor(), plsk) << std::endl;
280  s << "recruitment_diversity: " << this->ai_->get_recruitment_diversity() << std::endl;
281  s << "recruitment_instructions: " << std::endl << "----config begin----" << std::endl;
282  s << this->ai_->get_recruitment_instructions() << "-----config end-----" << std::endl;
283  s << "recruitment_more: " << utils::join(this->ai_->get_recruitment_more()) << std::endl;
284  s << "recruitment_pattern: " << utils::join(this->ai_->get_recruitment_pattern()) << std::endl;
285  s << "recruitment_randomness: " << this->ai_->get_recruitment_randomness() << std::endl;
286  s << "recruitment_save_gold: " << std::endl << "----config begin----" << std::endl;
287  s << this->ai_->get_recruitment_save_gold() << "-----config end-----" << std::endl;
288  s << "retreat_enemy_weight: " << this->ai_->get_retreat_enemy_weight() << std::endl;
289  s << "retreat_factor: " << this->ai_->get_retreat_factor() << std::endl;
290  s << "scout_village_targeting: " << this->ai_->get_scout_village_targeting() << std::endl;
291  s << "simple_targeting: " << cfg["simple_targeting"] << std::endl;
292  s << "support_villages: " << cfg["support_villages"] << std::endl;
293  s << "village_value: " << this->ai_->get_village_value() << std::endl;
294  s << "villages_per_scout: " << this->ai_->get_villages_per_scout() << std::endl;
295 
296  return s.str();
297 }
298 
299 const std::string holder::get_ai_structure()
300 {
301  if (!this->ai_) {
302  get_ai_ref();
303  }
304  return component_manager::print_component_tree(&*this->ai_,"");
305 }
306 
307 const std::string holder::get_ai_identifier() const
308 {
309  return cfg_["id"];
310 }
311 
312 component* holder::get_component(component *root, const std::string &path) {
313  if (!game_config::debug) // Debug guard
314  {
315  return nullptr;
316  }
317 
318  if (root == nullptr) // Return root component(ai_)
319  {
320  if (!this->ai_) {
321  this->init(this->side_);
322  }
323  assert(this->ai_);
324 
325  return &*this->ai_;
326  }
327 
329 }
330 
331 // =======================================================================
332 // LIFECYCLE
333 // =======================================================================
334 
336  : history_()
337  , history_item_counter_(0)
338  , ai_info_()
339  , map_changed_("ai_map_changed")
340  , recruit_list_changed_("ai_recruit_list_changed")
341  , user_interact_("ai_user_interact")
342  , sync_network_("ai_sync_network")
343  , tod_changed_("ai_tod_changed")
344  , gamestate_changed_("ai_gamestate_changed")
345  , turn_started_("ai_turn_started")
346  , last_interact_(0)
347  , num_interact_(0)
348 {
349  registry::init();
350  singleton_ = this;
351 }
352 
353 manager* manager::singleton_ = nullptr;
354 
356  user_interact_.attach_handler(event_observer);
357  sync_network_.attach_handler(event_observer);
358  turn_started_.attach_handler(event_observer);
359  gamestate_changed_.attach_handler(event_observer);
360 }
361 
363  user_interact_.detach_handler(event_observer);
364  sync_network_.detach_handler(event_observer);
365  turn_started_.detach_handler(event_observer);
366  gamestate_changed_.detach_handler(event_observer);
367 }
368 
370  gamestate_changed_.attach_handler(event_observer);
371  turn_started_.attach_handler(event_observer);
372  map_changed_.attach_handler(event_observer);
373 }
374 
376  gamestate_changed_.detach_handler(event_observer);
377  turn_started_.detach_handler(event_observer);
378  map_changed_.detach_handler(event_observer);
379 }
380 
382  tod_changed_.attach_handler(event_observer);
383 }
384 
386  tod_changed_.detach_handler(event_observer);
387 }
388 
390 {
391  map_changed_.attach_handler(event_observer);
392 }
393 
395 {
396  recruit_list_changed_.attach_handler(event_observer);
397 }
398 
400 {
401  turn_started_.attach_handler(event_observer);
402 }
403 
405 {
406  recruit_list_changed_.detach_handler(event_observer);
407 }
408 
410 {
411  map_changed_.detach_handler(event_observer);
412 }
413 
415 {
416  turn_started_.detach_handler(event_observer);
417 }
418 
421  return;
422  }
423 
424  const int interact_time = 30;
425  const int time_since_interact = SDL_GetTicks() - last_interact_;
426  if(time_since_interact < interact_time) {
427  return;
428  }
429 
430  ++num_interact_;
432 
433  last_interact_ = SDL_GetTicks();
434 
435 }
436 
439 }
440 
443 }
444 
447 }
448 
451 }
452 
455 }
456 
459 }
460 
461 // =======================================================================
462 // EVALUATION
463 // =======================================================================
464 
465 const std::string manager::evaluate_command( side_number side, const std::string& str )
466 {
467  //insert new command into history
468  history_.emplace_back(history_item_counter_++,str);
469 
470  //prune history - erase 1/2 of it if it grows too large
471  if (history_.size()>MAX_HISTORY_SIZE){
472  history_.erase(history_.begin(),history_.begin()+MAX_HISTORY_SIZE/2);
473  LOG_AI_MANAGER << "AI MANAGER: pruned history";
474  }
475 
476  if (!should_intercept(str)){
479  return ai.evaluate(str);
480  }
481 
482  return internal_evaluate_command(side,str);
483 }
484 
485 bool manager::should_intercept( const std::string& str ) const
486 {
487  if (str.length()<1) {
488  return false;
489  }
490  if (str.at(0)=='!'){
491  return true;
492  }
493  if (str.at(0)=='?'){
494  return true;
495  }
496  return false;
497 
498 }
499 
500 // this is stub code to allow testing of basic 'history', 'repeat-last-command', 'add/remove/replace ai' capabilities.
501 // yes, it doesn't look nice. but it is usable.
502 // to be refactored at earliest opportunity
503 // TODO: extract to separate class which will use fai or lua parser
504 const std::string manager::internal_evaluate_command( side_number side, const std::string& str ){
505  const int MAX_HISTORY_VISIBLE = 30;
506 
507  //repeat last command
508  if (str=="!") {
509  //this command should not be recorded in history
510  if (!history_.empty()){
511  history_.pop_back();
513  }
514 
515  if (history_.empty()){
516  return "AI MANAGER: empty history";
517  }
518  return evaluate_command(side, history_.back().get_command());//no infinite loop since '!' commands are not present in history
519  };
520  //show last command
521  if (str=="?") {
522  //this command should not be recorded in history
523  if (!history_.empty()){
524  history_.pop_back();
526  }
527 
528  if (history_.empty()){
529  return "AI MANAGER: History is empty";
530  }
531 
532  int n = std::min<int>( MAX_HISTORY_VISIBLE, history_.size() );
533  std::stringstream strstream;
534  strstream << "AI MANAGER: History - last "<< n <<" commands:\n";
535  std::deque< command_history_item >::reverse_iterator j = history_.rbegin();
536 
537  for (int cmd_id=n; cmd_id>0; --cmd_id){
538  strstream << j->get_number() << " :" << j->get_command() << '\n';
539  ++j;//this is *reverse* iterator
540  }
541 
542  return strstream.str();
543  };
544 
545  std::vector< std::string > cmd = utils::parenthetical_split(str, ' ',"'","'");
546 
547  if (cmd.size()==3){
548  // add_ai side file
549  if (cmd.at(0)=="!add_ai"){
550  side = std::stoi(cmd.at(1));
551  std::string file = cmd.at(2);
552  if (add_ai_for_side_from_file(side,file,false)){
553  return std::string("AI MANAGER: added [")+manager::get_active_ai_identifier_for_side(side)+std::string("] AI for side ")+std::to_string(side)+std::string(" from file ")+file;
554  } else {
555  return std::string("AI MANAGER: failed attempt to add AI for side ")+std::to_string(side)+std::string(" from file ")+file;
556  }
557  }
558  // replace_ai side file
559  if (cmd.at(0)=="!replace_ai"){
560  side = std::stoi(cmd.at(1));
561  std::string file = cmd.at(2);
562  if (add_ai_for_side_from_file(side,file,true)){
563  return std::string("AI MANAGER: added [")+manager::get_active_ai_identifier_for_side(side)+std::string("] AI for side ")+std::to_string(side)+std::string(" from file ")+file;
564  } else {
565  return std::string("AI MANAGER: failed attempt to add AI for side ")+std::to_string(side)+std::string(" from file ")+file;
566  }
567  }
568 
569  } else if (cmd.size()==2){
570  // remove_ai side
571  if (cmd.at(0)=="!remove_ai"){
572  side = std::stoi(cmd.at(1));
573  remove_ai_for_side(side);
574  return std::string("AI MANAGER: made an attempt to remove AI for side ")+std::to_string(side);
575  }
576  if (cmd.at(0)=="!"){
577  //this command should not be recorded in history
578  if (!history_.empty()){
579  history_.pop_back();
581  }
582 
583  int command = std::stoi(cmd.at(1));
584  std::deque< command_history_item >::reverse_iterator j = history_.rbegin();
585  //yes, the iterator could be precisely positioned (since command numbers go 1,2,3,4,..). will do it later.
586  while ( (j!=history_.rend()) && (j->get_number()!=command) ){
587  ++j;// this is *reverse* iterator
588  }
589  if (j!=history_.rend()){
590  return evaluate_command(side,j->get_command());//no infinite loop since '!' commands are not present in history
591  }
592  return "AI MANAGER: no command with requested number found";
593  }
594  } else if (cmd.size()==1){
595  if (cmd.at(0)=="!help") {
596  return
597  "known commands:\n"
598  "! - repeat last command (? and ! do not count)\n"
599  "! NUMBER - repeat numbered command\n"
600  "? - show a history list\n"
601  "!add_ai TEAM FILE - add a AI to side (0 - command AI, N - AI for side #N) from file\n"
602  "!remove_ai TEAM - remove AI from side (0 - command AI, N - AI for side #N)\n"
603  "!replace_ai TEAM FILE - replace AI of side (0 - command AI, N - AI for side #N) from file\n"
604  "!help - show this help message";
605  }
606  }
607 
608  return "AI MANAGER: nothing to do";
609 }
610 
611 // =======================================================================
612 // ADD, CREATE AIs, OR LIST AI TYPES
613 // =======================================================================
614 
615 bool manager::add_ai_for_side_from_file( side_number side, const std::string& file, bool replace )
616 {
617  config cfg;
619  ERR_AI_MANAGER << " unable to read [SIDE] config for side "<< side << "from file [" << file <<"]";
620  return false;
621  }
622  return add_ai_for_side_from_config(side,cfg,replace);
623 }
624 
625 bool manager::add_ai_for_side_from_config( side_number side, const config& cfg, bool replace ){
626  config parsed_cfg;
627  configuration::parse_side_config(side, cfg, parsed_cfg);
628 
629  if (replace) {
630  remove_ai_for_side(side);
631  }
632 
633  std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
634  ai_stack_for_specific_side.emplace(side, parsed_cfg);
635  return true;
636 }
637 
638 // =======================================================================
639 // REMOVE
640 // =======================================================================
641 
643 {
644  std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
645  if (!ai_stack_for_specific_side.empty()){
646  ai_stack_for_specific_side.pop();
647  }
648 }
649 
651 {
652  std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
653 
654  //clear the stack. std::stack doesn't have a '.clear()' method to do it
655  while (!ai_stack_for_specific_side.empty()){
656  ai_stack_for_specific_side.pop();
657  }
658 }
659 
661 {
662  ai_map_.clear();
663 }
664 
666 {
668 }
669 
671 {
673 }
674 
676 {
678 }
679 
681 {
683 }
684 
686 {
688 }
689 
691 {
692  if (!game_config::debug)
693  {
694  static ai::holder empty_holder(side, config());
695  return empty_holder;
696  }
697  return get_active_ai_holder_for_side(side);
698 }
699 
701 {
703 }
704 
706 {
707  return ai_info_;
708 }
709 
711 {
712  return ai_info_;
713 }
714 
716 {
718 }
719 
720 // =======================================================================
721 // PROXY
722 // =======================================================================
723 
725  last_interact_ = 0;
726  num_interact_ = 0;
727  const int turn_start_time = SDL_GetTicks();
728  get_ai_info().recent_attacks.clear();
729  ai_composite& ai_obj = get_active_ai_for_side(side);
730  resources::game_events->pump().fire("ai_turn");
732  if (resources::tod_manager->has_tod_bonus_changed()) {
734  }
735  ai_obj.new_turn();
736  ai_obj.play_turn();
737  const int turn_end_time= SDL_GetTicks();
738  DBG_AI_MANAGER << "side " << side << ": number of user interactions: "<<num_interact_;
739  DBG_AI_MANAGER << "side " << side << ": total turn time: "<<turn_end_time - turn_start_time << " ms ";
740 }
741 
742 // =======================================================================
743 // PRIVATE
744 // =======================================================================
745 // =======================================================================
746 // AI STACKS
747 // =======================================================================
749 {
750  AI_map_of_stacks::iterator iter = ai_map_.find(side);
751  if (iter!=ai_map_.end()){
752  return iter->second;
753  }
754  return ai_map_.emplace(side, std::stack<holder>()).first->second;
755 }
756 
757 // =======================================================================
758 // AI HOLDERS
759 // =======================================================================
761 {
762  std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
763 
764  if (!ai_stack_for_specific_side.empty()){
765  return ai_stack_for_specific_side.top();
766  } else {
768  ai_stack_for_specific_side.emplace(side, cfg);
769  return ai_stack_for_specific_side.top();
770  }
771 }
772 
773 // =======================================================================
774 // AI POINTERS
775 // =======================================================================
776 
778 {
780 }
781 
782 // =======================================================================
783 // MISC
784 // =======================================================================
785 
786 } //end of namespace ai
#define LOG_AI_MOD
Definition: manager.cpp:70
#define DBG_AI_MOD
Definition: manager.cpp:69
#define ERR_AI_MOD
Definition: manager.cpp:72
#define LOG_AI_MANAGER
Definition: manager.cpp:65
#define DBG_AI_MANAGER
Definition: manager.cpp:64
#define ERR_AI_MANAGER
Definition: manager.cpp:66
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands.
virtual void new_turn()
On new turn.
Definition: ai.cpp:174
void play_turn()
Play the turn.
Definition: ai.cpp:140
static bool delete_component(component *root, const std::string &path)
Definition: component.cpp:201
static component * get_component(component *root, const std::string &path)
Definition: component.cpp:249
static bool change_component(component *root, const std::string &path, const config &cfg)
Definition: component.cpp:187
static bool add_component(component *root, const std::string &path, const config &cfg)
Definition: component.cpp:172
static std::string print_component_tree(component *root, const std::string &path)
Definition: component.cpp:231
static bool get_side_config_from_file(const std::string &file, config &cfg)
get side config from file
static bool parse_side_config(side_number side, const config &original_cfg, config &cfg)
static const config & get_default_ai_parameters()
get default AI parameters
std::set< map_location > recent_attacks
Definition: game_info.hpp:115
Base class that holds the AI and current AI parameters.
Definition: manager.hpp:50
config to_config() const
Definition: manager.cpp:221
composite_ai_ptr ai_
Definition: manager.hpp:78
void micro_ai(const config &cfg)
Definition: manager.cpp:147
void modify_ai(const config &cfg)
Definition: manager.cpp:160
config cfg_
Definition: manager.hpp:84
ai_composite & get_ai_ref()
Definition: manager.cpp:137
virtual ~holder()
Definition: manager.cpp:128
component * get_component(component *root, const std::string &path)
Definition: manager.cpp:312
const std::string get_ai_overview()
Definition: manager.cpp:255
std::unique_ptr< side_context > side_context_
Definition: manager.hpp:79
const std::string get_ai_identifier() const
Definition: manager.cpp:307
side_number side_
Definition: manager.hpp:83
std::unique_ptr< readwrite_context > readwrite_context_
Definition: manager.hpp:81
const std::string get_ai_structure()
Definition: manager.cpp:299
std::unique_ptr< readonly_context > readonly_context_
Definition: manager.hpp:80
const std::string describe_ai()
Definition: manager.cpp:244
void init(side_number side)
Definition: manager.cpp:80
void append_ai(const config &cfg)
Definition: manager.cpp:189
std::unique_ptr< default_ai_context > default_ai_context_
Definition: manager.hpp:82
holder(side_number side, const config &cfg)
Definition: manager.cpp:74
Class that manages AIs for all sides and manages AI redeployment.
Definition: manager.hpp:111
static const std::string AI_TYPE_SAMPLE_AI
Definition: manager.hpp:121
events::generic_event map_changed_
Definition: manager.hpp:427
std::string get_active_ai_identifier_for_side(side_number side)
Gets AI algorithm identifier for active AI of the given side.
Definition: manager.cpp:685
void clear_ais()
Clears all the AIs.
Definition: manager.cpp:660
std::string get_active_ai_overview_for_side(side_number side)
Gets AI Overview for active AI of the given side.
Definition: manager.cpp:675
ai_composite & get_active_ai_for_side(side_number side)
Gets active AI for specified side.
Definition: manager.cpp:777
void raise_tod_changed()
Notifies all observers of 'ai_tod_changed' event.
Definition: manager.cpp:445
bool add_ai_for_side_from_config(side_number side, const config &cfg, bool replace=true)
Adds active AI for specified side from cfg.
Definition: manager.cpp:625
config to_config(side_number side)
Gets AI config for active AI of the given side.
Definition: manager.cpp:700
events::generic_event user_interact_
Definition: manager.hpp:429
void remove_all_ais_for_side(side_number side)
Removes all AIs from side.
Definition: manager.cpp:650
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:375
void remove_observer(events::observer *event_observer)
Removes an observer of game events.
Definition: manager.cpp:362
void raise_turn_started()
Notifies all observers of 'ai_turn_started' event.
Definition: manager.cpp:449
static manager * singleton_
Definition: manager.hpp:439
static const std::string AI_TYPE_IDLE_AI
Definition: manager.hpp:122
static const std::string AI_TYPE_COMPOSITE_AI
Definition: manager.hpp:120
static const std::size_t MAX_HISTORY_SIZE
Definition: manager.hpp:118
void raise_gamestate_changed()
Notifies all observers of 'ai_gamestate_changed' event.
Definition: manager.cpp:441
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:369
void append_active_ai_for_side(ai::side_number side, const config &cfg)
Appends AI parameters to active AI of the given side.
Definition: manager.cpp:670
AI_map_of_stacks ai_map_
Definition: manager.hpp:437
std::string get_active_ai_structure_for_side(side_number side)
Gets AI Structure for active AI of the given side.
Definition: manager.cpp:680
events::generic_event sync_network_
Definition: manager.hpp:430
void raise_user_interact()
Notifies all observers of 'ai_user_interact' event.
Definition: manager.cpp:419
static const std::string AI_TYPE_FORMULA_AI
Definition: manager.hpp:123
events::generic_event recruit_list_changed_
Definition: manager.hpp:428
const std::string evaluate_command(side_number side, const std::string &str)
Evaluates a string command using command AI.
Definition: manager.cpp:465
std::stack< holder > & get_or_create_ai_stack_for_side(side_number side)
Gets the AI stack for the specified side, create it if it doesn't exist.
Definition: manager.cpp:748
holder & get_active_ai_holder_for_side(side_number side)
Gets active holder for specified side.
Definition: manager.cpp:760
void add_recruit_list_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_recruit_list_changed' event.
Definition: manager.cpp:394
game_info & get_active_ai_info_for_side(side_number side)
Gets AI info for active AI of the given side.
Definition: manager.cpp:705
void add_map_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_map_changed' event.
Definition: manager.cpp:389
void add_turn_started_observer(events::observer *event_observer)
Adds an observer of 'ai_turn_started' event.
Definition: manager.cpp:399
static const std::string AI_TYPE_DEFAULT
Definition: manager.hpp:126
std::deque< command_history_item > history_
Definition: manager.hpp:423
game_info & get_ai_info()
Gets global AI-game info.
Definition: manager.cpp:710
game_info ai_info_
Definition: manager.hpp:425
events::generic_event gamestate_changed_
Definition: manager.hpp:432
const ai::unit_advancements_aspect & get_advancement_aspect_for_side(side_number side)
Definition: manager.cpp:715
bool add_ai_for_side_from_file(side_number side, const std::string &file, bool replace=true)
Adds active AI for specified side from file.
Definition: manager.cpp:615
events::generic_event turn_started_
Definition: manager.hpp:433
void remove_ai_for_side(side_number side)
Removes top-level AI from side.
Definition: manager.cpp:642
void modify_active_ai_for_side(ai::side_number side, const config &cfg)
Modifies AI parameters for active AI of the given side.
Definition: manager.cpp:665
int last_interact_
Definition: manager.hpp:434
int num_interact_
Definition: manager.hpp:435
void play_turn(side_number side)
Plays a turn for the specified side using its active AI.
Definition: manager.cpp:724
const std::string internal_evaluate_command(side_number side, const std::string &str)
Evaluates an internal manager command.
Definition: manager.cpp:504
long history_item_counter_
Definition: manager.hpp:424
void raise_map_changed()
Notifies all observers of 'ai_map_changed' event.
Definition: manager.cpp:457
bool should_intercept(const std::string &str) const
Determines if the command should be intercepted and evaluated as internal command.
Definition: manager.cpp:485
void raise_recruit_list_changed()
Notifies all observers of 'ai_recruit_list_changed' event.
Definition: manager.cpp:453
void remove_turn_started_observer(events::observer *event_observer)
Deletes an observer of 'ai_turn_started' event.
Definition: manager.cpp:414
ai::holder & get_active_ai_holder_for_side_dbg(side_number side)
Gets the active AI holder for debug purposes.
Definition: manager.cpp:690
void raise_sync_network()
Notifies all observers of 'ai_sync_network' event.
Definition: manager.cpp:437
events::generic_event tod_changed_
Definition: manager.hpp:431
void remove_map_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_map_changed' event.
Definition: manager.cpp:409
void add_tod_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_tod_changed' event.
Definition: manager.cpp:381
void remove_tod_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_tod_changed' event.
Definition: manager.cpp:385
void add_observer(events::observer *event_observer)
Adds observer of game events.
Definition: manager.cpp:355
void remove_recruit_list_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_recruit_list_changed' event.
Definition: manager.cpp:404
virtual const unit_advancements_aspect & get_advancements() const override
Definition: contexts.hpp:541
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
void clear_children(T... keys)
Definition: config.hpp:642
void merge_with(const config &c)
Merge config 'c' into this config, overwriting this config's values.
Definition: config.cpp:1126
child_itors child_range(config_key_type key)
Definition: config.cpp:273
virtual bool attach_handler(observer *obs)
virtual bool detach_handler(observer *obs)
virtual void notify_observers()
game_events::wml_event_pump & pump()
Definition: manager.cpp:253
pump_result_t fire(const std::string &event, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Function to fire an event.
Definition: pump.cpp:399
A component of the AI framework.
Composite AI with turn sequence which is a vector of stages.
Managing the AIs configuration - headers.
Helper functions for the object which operates in the context of AI for specific side this is part of...
Default AI contexts.
AI Support engine - creating specific ai components from config.
LUA AI Support engine - creating specific ai components from config.
formula_ai & ai_
Game information for the AI.
Standard logging facilities (interface).
void init()
Definition: registry.cpp:504
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:59
static lg::log_domain log_ai_mod("ai/mod")
static lg::log_domain log_ai_manager("ai/manager")
int side_number
Definition: game_info.hpp:40
std::string path
Definition: filesystem.cpp:84
const bool & debug
Definition: game_config.cpp:91
::tod_manager * tod_manager
Definition: resources.cpp:29
bool simulation_
Definition: resources.cpp:35
game_events::manager * game_events
Definition: resources.cpp:24
std::vector< std::string > parenthetical_split(std::string_view val, const char separator, std::string_view left, std::string_view right, const int flags)
Splits a string based either on a separator, except then the text appears within specified parenthesi...
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
Define the game's event mechanism.
All known AI parts.
static map_location::DIRECTION n
static map_location::DIRECTION s