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