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