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