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