The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
actions.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2016 by Yurii Chernyi <[email protected]>
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-Game interaction - AI actions and their results
17  * @file
18  */
19 
20 /**
21  * A small explanation about what's going on here:
22  * Each action has access to two game_info objects
23  * First is 'info' - real information
24  * Second is 'subjective info' - AIs perception of what's going on
25  * So, when we check_before action, we use 'subjective info' and don't
26  * touch real 'info' at all.
27  * But when we actually want to execute an action, we firstly check
28  * 'subjective info' and then (if subjective check is ok) do the same
29  * check on real 'info'. There's a caveat: if we fail an action based
30  * on real 'info', then we NEED to update AIs knowledge to avoid the ai
31  * doing the same thing again.
32  * So far the use of 'subjective info' is stubbed out.
33  */
34 
35 #include "ai/actions.hpp"
36 #include "ai/manager.hpp"
37 #include "ai/simulated_actions.hpp"
38 
39 #include "actions/attack.hpp"
40 #include "actions/create.hpp"
41 #include "attack_prediction.hpp"
42 #include "game_preferences.hpp"
43 #include "log.hpp"
44 #include "mouse_handler_base.hpp"
45 #include "pathfind/teleport.hpp"
46 #include "play_controller.hpp"
48 #include "recall_list_manager.hpp"
49 #include "replay_helper.hpp"
50 #include "resources.hpp"
51 #include "synced_context.hpp"
52 #include "team.hpp"
53 #include "units/unit.hpp"
54 #include "units/ptr.hpp"
55 #include "whiteboard/manager.hpp"
56 
57 namespace ai {
58 
59 static lg::log_domain log_ai_actions("ai/actions");
60 #define DBG_AI_ACTIONS LOG_STREAM(debug, log_ai_actions)
61 #define LOG_AI_ACTIONS LOG_STREAM(info, log_ai_actions)
62 #define WRN_AI_ACTIONS LOG_STREAM(warn, log_ai_actions)
63 #define ERR_AI_ACTIONS LOG_STREAM(err, log_ai_actions)
64 
65 // =======================================================================
66 // AI ACTIONS
67 // =======================================================================
69  : return_value_checked_(true),side_(side),status_(AI_ACTION_SUCCESS),is_execution_(false),is_gamestate_changed_(false)
70 {
71 }
72 
74 {
75  if (!return_value_checked_) {
76  ERR_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs! " << std::endl;
77  }
78 }
79 
81 {
83 }
84 
86 {
88 }
89 
91 {
92  is_execution_ = true;
94  check_before();
95  if (is_success()){
96  try {
97  do_execute();
98  } catch (return_to_play_side_exception&) {
99  if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs! " << std::endl; } //Demotes to DBG "unchecked result" warning
100  throw;
101  }
102  }
103  if (is_success()){
104  check_after();
105  }
106  is_execution_ = false;
107 }
108 
110 {
111  return_value_checked_ = false;
112  is_gamestate_changed_ = false;
115 }
116 
118 {
119  return is_gamestate_changed_;
120 }
121 
123 {
124  return_value_checked_ = true;
125  return is_success();
126 }
127 
128 void action_result::set_error(int error_code, bool log_as_error){
129  status_ = error_code;
130  if (is_execution()) {
131  if (log_as_error) {
132  ERR_AI_ACTIONS << "Error #"<<error_code<<" ("<<actions::get_error_name(error_code)<<") in "<< do_describe();
133  } else {
134  LOG_AI_ACTIONS << "Error #"<<error_code<<" ("<<actions::get_error_name(error_code)<<") in "<< do_describe();
135  }
136  } else {
137  LOG_AI_ACTIONS << "Error #"<<error_code<<" ("<<actions::get_error_name(error_code)<<") when checking "<< do_describe();
138  }
139 }
140 
142 {
143  is_gamestate_changed_ = true;
144 }
145 
147 {
148  return status_;
149 }
150 
152 {
154 }
155 
157 {
158  return is_execution_;
159 }
160 
162 {
164 }
165 
167 {
168  return (*resources::teams)[side_-1];
169 }
170 
171 
172 // attack_result
173 attack_result::attack_result( side_number side, const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon, double aggression, const unit_advancements_aspect& advancements)
174  : action_result(side), attacker_loc_(attacker_loc), defender_loc_(defender_loc), attacker_weapon_(attacker_weapon), aggression_(aggression), advancements_(advancements){
175 }
176 
178 {
179  LOG_AI_ACTIONS << " check_before " << *this << std::endl;
182 
183  if(attacker==resources::units->end())
184  {
185  LOG_AI_ACTIONS << "attempt to attack without attacker\n";
187  return;
188  }
189 
190  if (defender==resources::units->end())
191  {
192  LOG_AI_ACTIONS << "attempt to attack without defender\n";
194  return;
195  }
196 
197  if(attacker->incapacitated()) {
198  LOG_AI_ACTIONS << "attempt to attack with unit that is petrified\n";
200  return;
201  }
202 
203  if(defender->incapacitated()) {
204  LOG_AI_ACTIONS << "attempt to attack unit that is petrified\n";
206  return;
207  }
208 
209  if(!attacker->attacks_left()) {
210  LOG_AI_ACTIONS << "attempt to attack with no attacks left\n";
212  return;
213  }
214 
215  if(attacker->side()!=get_side()) {
216  LOG_AI_ACTIONS << "attempt to attack with not own unit\n";
218  return;
219  }
220 
221  if(!get_my_team().is_enemy(defender->side())) {
222  LOG_AI_ACTIONS << "attempt to attack unit that is not enemy\n";
224  return;
225  }
226 
227  if (attacker_weapon_!=-1) {
228  if ((attacker_weapon_<0)||(attacker_weapon_ >= static_cast<int>(attacker->attacks().size()))) {
229  LOG_AI_ACTIONS << "invalid weapon selection for the attacker\n";
231  return;
232  }
233  }
234 
236  LOG_AI_ACTIONS << "attacker and defender not adjacent\n";
238  return;
239  }
240 }
241 
243 {
244 }
245 
247 {
248  std::stringstream s;
249  s << "attack by side ";
250  s << get_side();
251  s << " from location "<<attacker_loc_;
252  s << " to location "<<defender_loc_;
253  s << " using weapon "<< attacker_weapon_;
254  s << " with aggression "<< aggression_;
255  s <<std::endl;
256  return s.str();
257 }
258 
260 {
261  LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl;
262  // Stop the user from issuing any commands while the unit is attacking
263  const events::command_disabler disable_commands;
264  //@note: yes, this is a decision done here. It's that way because we want to allow a simpler attack 'with whatever weapon is considered best', and because we want to allow the defender to pick it's weapon. That's why aggression is needed. a cleaner solution is needed.
267 
268  int attacker_weapon = bc.get_attacker_stats().attack_num;
269  int defender_weapon = bc.get_defender_stats().attack_num;
270 
271  if(attacker_weapon < 0) {
273  return;
274  }
275 
278 
281 
282  sim_gamestate_changed(this, gamestate_changed);
283 
284  return;
285  }
286 
287  //FIXME: find a way to 'ask' the ai which advancement should be chosen from synced_commands.cpp .
288  if(!synced_context::is_synced()) //RAII block for set_scontext_synced
289  {
290  wb::real_map rm;
291  //we don't use synced_context::run_in_synced_context because that wouldn't allow us to pass advancements_
292  resources::recorder->add_synced_command("attack", replay_helper::get_attack(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, a_->type_id(),
293  d_->type_id(), a_->level(), d_->level(), resources::tod_manager->turn(),
295  set_scontext_synced sync;
296  attack_unit_and_advance(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, true, advancements_);
299  sync.do_final_checkup();
300  }
301  else
302  {
303  attack_unit_and_advance(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, true, advancements_);
304  }
305 
306 
308  //start of ugly hack. @todo 1.9 rework that via extended event system
309  //until event system is reworked, we note the attack this way
311  //end of ugly hack
312  try {
314  } catch (...) {
315  if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs! " << std::endl; } //Demotes to DBG "unchecked result" warning
316  throw;
317  }
318 }
319 
321 {
322 }
323 
324 
325 // move_result
327  const map_location& to, bool remove_movement, bool unreach_is_ok)
328  : action_result(side)
329  , from_(from)
330  , to_(to)
331  , remove_movement_(remove_movement)
332  , route_()
333  , unit_location_(from)
334  , unreach_is_ok_(unreach_is_ok)
335  , has_ambusher_(false)
336  , has_interrupted_teleport_(false)
337 {
338 }
339 
341 {
343  if (un==resources::units->end()){
345  return nullptr;
346  }
347  const unit *u = &*un;
348  if (u->side() != get_side()) {
350  return nullptr;
351  }
352  if (u->incapacitated()) {
354  return nullptr;
355  }
356  return u;
357 }
358 
360 {
361  if (from_== to_) {
362  if (!remove_movement_ || (un.movement_left() == 0) ) {
364  return false;
365  }
366  return true;
367  }
368 
369  if (un.movement_left() == 0 ) {
371  return false;
372  }
373 
374  if (!to_.valid()) {
376  return false;
377  }
378 
379  team &my_team = get_my_team();
381 
382  //allowed teleports
383  pathfind::teleport_map allowed_teleports = pathfind::get_teleport_locations(un, my_team, true);///@todo 1.9: see_all -> false
384 
385  //do an A*-search
387  if (route_->steps.empty()) {
389  return false;
390  }
391  return true;
392 }
393 
395 {
396  LOG_AI_ACTIONS << " check_before " << *this << std::endl;
397  const unit *u = get_unit();
398  if (!u) {
399  return;
400  }
401  if (!test_route(*u)) {
402  return;
403  }
404 }
405 
407 {
408  return unit_location_;
409 }
410 
412 {
413  if (has_ambusher_) {
414  set_error(E_AMBUSHED,false);
415  return;
416  }
419  return;
420  }
421  ///@todo 1.9 add 'new units spotted' failure mode
422 
423  if (!unreach_is_ok_ && unit_location_!=to_) {
425  return;
426  }
427 }
428 
430 {
431  std::stringstream s;
432  if (remove_movement_){
433  s << "full move by side ";
434  } else {
435  s << "partial move by side ";
436  }
437  s << get_side();
438  s << " from location "<<from_;
439  s << " to location "<<to_;
440  s <<std::endl;
441  return s.str();
442 }
443 
445 {
446  LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl;
447  assert(is_success());
448 
450  bool gamestate_changed = false;
451  if(from_ != to_){
452  int step = route_->steps.size();
453  gamestate_changed = simulated_move(get_side(), from_, to_, step, unit_location_);
454  } else {
455  assert(remove_movement_);
456  }
457 
459  if(remove_movement_ && un->movement_left() > 0 && unit_location_ == to_){
460  gamestate_changed = simulated_stopunit(unit_location_, true, false);
461  }
462 
463  sim_gamestate_changed(this, gamestate_changed);
464 
465  return;
466  }
467 
469  move_spectator.set_unit(resources::units->find(from_));
470 
471  if (from_ != to_) {
472  size_t num_steps = ::actions::move_unit_and_record(
473  /*std::vector<map_location> steps*/ route_->steps,
474  /*::actions::undo_list* undo_stack*/ nullptr,
475  /*bool continue_move*/ true, ///@todo 1.9 set to false after implemeting interrupt awareness
476  /*bool show_move*/ preferences::show_ai_moves(),
477  /*bool* interrupted*/ nullptr,
478  /*::actions::move_unit_spectator* move_spectator*/ &move_spectator);
479 
480  if ( num_steps > 0 ) {
482  } else if ( move_spectator.get_ambusher().valid() ) {
483  // Unlikely, but some types of strange WML (or bad pathfinding)
484  // could cause an ambusher to be found without moving.
486  }
487  } else {
488  assert(remove_movement_);
489  }
490 
491  if (move_spectator.get_unit().valid()){
492  unit_location_ = move_spectator.get_unit()->get_location();
493  if (remove_movement_ && move_spectator.get_unit()->movement_left() > 0 && unit_location_ == to_)
494  {
496  if (!stopunit_res->is_ok()) {
497  set_error(stopunit_res->get_status());
498  }
499  if (stopunit_res->is_gamestate_changed()) {
501  }
502  }
503  } else {
505  }
506 
507  has_ambusher_ = move_spectator.get_ambusher().valid();
509 
510  if (is_gamestate_changed()) {
511  try {
513  } catch (...) {
514  if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs! " << std::endl; } //Demotes to DBG "unchecked result" warning
515  throw;
516  }
517  }
518 }
519 
521 {
522 }
523 
524 
525 // recall_result
527  const std::string& unit_id, const map_location& where, const map_location& from)
528  : action_result(side)
529  , unit_id_(unit_id)
530  , where_(where)
531  , recall_location_(where)
532  , recall_from_(from)
533  , location_checked_(false)
534 {
535 }
536 
538 {
540  if (!rec) {
542  }
543  return rec;
544 }
545 
547 {
548  if (my_team.gold() < my_team.recall_cost() ) {
550  return false;
551  }
552  return true;
553 }
554 
556 {
557  LOG_AI_ACTIONS << " check_before " << *this << std::endl;
558  const team& my_team = get_my_team();
559  const bool location_specified = recall_location_.valid();
560 
561  //Enough gold?
562  if (!test_enough_gold(my_team)) {
563  return;
564  }
565 
566  //Unit available for recalling?
567  const unit_const_ptr & to_recall = get_recall_unit(my_team);
568  if ( !to_recall ) {
569  return;
570  }
571 
572  // Leader available for recalling?
574  recall_from_, *to_recall) )
575  {
579  return;
580 
583  return;
584 
587  return;
588 
590  if ( location_specified ) {
592  return;
593  }
594  // No break. If the location was not specified, this counts as "OK".
596  location_checked_ = true;
597  }
598 }
599 
601 {
602  if (!resources::gameboard->map().on_board(recall_location_)){
604  return;
605  }
606 
608  if (unit==resources::units->end()){
610  return;
611  }
612  if (unit->side() != get_side()){
614  return;
615  }
616 }
617 
619 {
620  std::stringstream s;
621  s << "recall by side ";
622  s << get_side();
623  s << " of unit id ["<<unit_id_;
625  s << "] on location "<<where_;
626  } else {
627  s << "] on any suitable location";
628  }
629  s <<std::endl;
630  return s.str();
631 }
632 
634 {
635  LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl;
636  assert(is_success());
637 
638  const events::command_disabler disable_commands;
639 
640  // Assert that recall_location_ has been validated.
641  // This should be implied by is_success() once check_before() has been
642  // called, so this is a guard against future breakage.
643  assert(location_checked_);
644 
646  bool gamestate_changed = simulated_recall(get_side(), unit_id_, recall_location_);
647 
648  sim_gamestate_changed(this, gamestate_changed);
649 
650  return;
651  }
652 
653  // Do the actual recalling.
654  // We ignore possible errors (=unit doesn't exist on the recall list)
655  // because that was the previous behavior.
658  false,
661 
663  try {
665  } catch (...) {
666  if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs! " << std::endl; } //Demotes to DBG "unchecked result" warning
667  throw;
668  }
669 }
670 
672 {
673 }
674 
675 
676 // recruit_result
678  const std::string& unit_name, const map_location& where, const map_location& from)
679  : action_result(side)
680  , unit_name_(unit_name)
681  , where_(where)
682  , recruit_location_(where)
683  , recruit_from_(from)
684  , location_checked_(false)
685 {
686 }
687 
689 {
690  const unit_type *type = unit_types.find(recruit);
691  if (!type) {
693  return nullptr;
694  }
695  return type;
696 }
697 
699 {
700  if (my_team.gold() < type.cost()) {
702  return false;
703  }
704  return true;
705 }
706 
708 {
709  LOG_AI_ACTIONS << " check_before " << *this << std::endl;
710  const team& my_team = get_my_team();
711  const bool location_specified = recruit_location_.valid();
712 
713  //Unit type known ?
714  const unit_type *s_type = get_unit_type_known(unit_name_);
715  if (!s_type) {
716  return;
717  }
718 
719  //Enough gold?
720  if (!test_enough_gold(my_team, *s_type)) {
721  return;
722  }
723 
724  // Leader available for recruiting?
727  {
731  return;
732 
735  return;
736 
739  return;
740 
742  if ( location_specified ) {
744  return;
745  }
746  // No break. If the location was not specified, this counts as "OK".
748  location_checked_ = true;
749  }
750 }
751 
753 {
754  if (!resources::gameboard->map().on_board(recruit_location_)) {
756  return;
757  }
758 
760  if (unit==resources::units->end()) {
762  return;
763  }
764  if (unit->side() != get_side()) {
766  return;
767  }
768 }
769 
771 {
772  std::stringstream s;
773  s << "recruitment by side ";
774  s << get_side();
775  s << " of unit type ["<<unit_name_;
777  s << "] on location "<<where_;
778  } else {
779  s << "] on any suitable location";
780  }
781  s <<std::endl;
782  return s.str();
783 }
784 
786 {
787  LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl;
788  assert(is_success());
789 
790  const unit_type *u = unit_types.find(unit_name_);
791  const events::command_disabler disable_commands;
792 
793  // Assert that recruit_location_ has been validated.
794  // This should be implied by is_success() once check_before() has been
795  // called, so this is a guard against future breakage.
796  assert(location_checked_ && u != nullptr);
797 
799  bool gamestate_changed = simulated_recruit(get_side(), u, recruit_location_);
800 
801  sim_gamestate_changed(this, gamestate_changed);
802 
803  return;
804  }
805 
807  //TODO: should we do something to pass use_undo = false in replays and ai moves ?
808  //::actions::recruit_unit(*u, get_side(), recruit_location_, recruit_from_,
809  // preferences::show_ai_moves(), false);
810 
812  try {
814  } catch (...) {
815  if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs! " << std::endl; } //Demotes to DBG "unchecked result" warning
816  throw;
817  }
818 }
819 
821 {
822 }
823 
824 
825 // stopunit_result
826 stopunit_result::stopunit_result( side_number side, const map_location& unit_location, bool remove_movement, bool remove_attacks)
827  : action_result(side), unit_location_(unit_location), remove_movement_(remove_movement), remove_attacks_(remove_attacks)
828 {
829 }
830 
832 {
834  if (un==resources::units->end()){
836  return nullptr;
837  }
838  const unit *u = &*un;
839  if (u->side() != get_side()) {
841  return nullptr;
842  }
843  if (u->incapacitated()) {
845  return nullptr;
846  }
847  return u;
848 }
849 
851 {
852  LOG_AI_ACTIONS << " check_before " << *this << std::endl;
853 
854  if (!get_unit()) {
855  return;
856  }
857 }
858 
860 {
862  if (un==resources::units->end()){
864  return;
865  }
866  if (remove_movement_ && un->movement_left() != 0) {
868  return;
869  }
870  if (remove_attacks_ && un->attacks_left() != 0) {
872  return;
873  }
874 }
875 
877 {
878  std::stringstream s;
879  s <<" stopunit by side ";
880  s << get_side();
881  if (remove_movement_){
882  s << " : remove movement ";
883  }
885  s << "and ";
886  }
887  if (remove_attacks_){
888  s << " remove attacks ";
889  }
890  s << "from unit on location "<<unit_location_;
891  s <<std::endl;
892  return s.str();
893 }
894 
896 {
897  LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl;
898  assert(is_success());
900 
903 
904  sim_gamestate_changed(this, gamestate_changed);
905 
906  return;
907  }
908 
909  try {
910  if (remove_movement_){
911  un->remove_movement_ai();
914  }
915  if (remove_attacks_){
916  un->remove_attacks_ai();
918  manager::raise_gamestate_changed();//to be on the safe side
919  }
920  } catch (...) {
921  if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs! " << std::endl; } //Demotes to DBG "unchecked result" warning
922  throw;
923  }
924 }
925 
927 {
928 }
929 
930 
931 // synced_command_result
933  : action_result(side), lua_code_(lua_code), location_(location)
934 {
935 }
936 
938 {
939  LOG_AI_ACTIONS << " check_before " << *this << std::endl;
940 }
941 
943 {
944 }
945 
947 {
948  std::stringstream s;
949  s <<" synced_command by side ";
950  s << get_side();
951  s <<std::endl;
952  return s.str();
953 }
954 
956 {
958  bool gamestate_changed = simulated_synced_command();
959 
960  sim_gamestate_changed(this, gamestate_changed);
961 
962  return;
963  }
964 
965  LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl;
966  assert(is_success());
967 
968  std::stringstream s;
970  s << "local x1 = " << location_.x << " local y1 = " << location_.y << " ";
971  }
972  s << lua_code_;
973 
975 
976  try {
979  } catch (...) {
980  if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs! " << std::endl; } //Demotes to DBG "unchecked result" warning
981  throw;
982  }
983 }
984 
986 {
987 }
988 
989 
990 // =======================================================================
991 // STATELESS INTERFACE TO AI ACTIONS
992 // =======================================================================
993 
995  bool execute,
996  const map_location& attacker_loc,
997  const map_location& defender_loc,
998  int attacker_weapon,
999  double aggression,
1000  const unit_advancements_aspect& advancements)
1001 {
1002  attack_result_ptr action(new attack_result(side,attacker_loc,defender_loc,attacker_weapon,aggression,advancements));
1003  execute ? action->execute() : action->check_before();
1004  return action;
1005 }
1006 
1008  bool execute,
1009  const map_location& from,
1010  const map_location& to,
1011  bool remove_movement,
1012  bool unreach_is_ok)
1013 {
1014  move_result_ptr action(new move_result(side,from,to,remove_movement,unreach_is_ok));
1015  execute ? action->execute() : action->check_before();
1016  return action;
1017 }
1018 
1020  bool execute,
1021  const std::string& unit_id,
1022  const map_location& where,
1023  const map_location& from)
1024 {
1025  recall_result_ptr action(new recall_result(side,unit_id,where,from));
1026  execute ? action->execute() : action->check_before();
1027  return action;
1028 }
1029 
1031  bool execute,
1032  const std::string& unit_name,
1033  const map_location& where,
1034  const map_location& from)
1035 {
1036  recruit_result_ptr action(new recruit_result(side,unit_name,where,from));
1037  execute ? action->execute() : action->check_before();
1038  return action;
1039 }
1040 
1042  bool execute,
1043  const map_location& unit_location,
1044  bool remove_movement,
1045  bool remove_attacks)
1046 {
1047  stopunit_result_ptr action(new stopunit_result(side,unit_location,remove_movement,remove_attacks));
1048  execute ? action->execute() : action->check_before();
1049  return action;
1050 }
1051 
1053  bool execute,
1054  const std::string& lua_code,
1055  const map_location& location)
1056 {
1057  synced_command_result_ptr action(new synced_command_result(side,lua_code,location));
1058  execute ? action->execute() : action->check_before();
1059  return action;
1060 }
1061 
1062 const std::string& actions::get_error_name(int error_code)
1063 {
1064  if (error_names_.empty()){
1065  error_names_.insert(std::make_pair(action_result::AI_ACTION_SUCCESS,"action_result::AI_ACTION_SUCCESS"));
1066  error_names_.insert(std::make_pair(action_result::AI_ACTION_STARTED,"action_result::AI_ACTION_STARTED"));
1067  error_names_.insert(std::make_pair(action_result::AI_ACTION_FAILURE,"action_result::AI_ACTION_FAILURE"));
1068 
1069  error_names_.insert(std::make_pair(attack_result::E_EMPTY_ATTACKER,"attack_result::E_EMPTY_ATTACKER"));
1070  error_names_.insert(std::make_pair(attack_result::E_EMPTY_DEFENDER,"attack_result::E_EMPTY_DEFENDER"));
1071  error_names_.insert(std::make_pair(attack_result::E_INCAPACITATED_ATTACKER,"attack_result::E_INCAPACITATED_ATTACKER"));
1072  error_names_.insert(std::make_pair(attack_result::E_INCAPACITATED_DEFENDER,"attack_result::E_INCAPACITATED_DEFENDER"));
1073  error_names_.insert(std::make_pair(attack_result::E_NOT_OWN_ATTACKER,"attack_result::E_NOT_OWN_ATTACKER"));
1074  error_names_.insert(std::make_pair(attack_result::E_NOT_ENEMY_DEFENDER,"attack_result::E_NOT_ENEMY_DEFENDER"));
1075  error_names_.insert(std::make_pair(attack_result::E_NO_ATTACKS_LEFT,"attack_result::E_NO_ATTACKS_LEFT"));
1076  error_names_.insert(std::make_pair(attack_result::E_WRONG_ATTACKER_WEAPON,"attack_result::E_WRONG_ATTACKER_WEAPON"));
1077  error_names_.insert(std::make_pair(attack_result::E_UNABLE_TO_CHOOSE_ATTACKER_WEAPON,"attack_result::E_UNABLE_TO_CHOOSE_ATTACKER_WEAPON"));
1078  error_names_.insert(std::make_pair(attack_result::E_ATTACKER_AND_DEFENDER_NOT_ADJACENT,"attack_result::E_ATTACKER_AND_DEFENDER_NOT_ADJACENT"));
1079 
1080  error_names_.insert(std::make_pair(move_result::E_EMPTY_MOVE,"move_result::E_EMPTY_MOVE"));
1081  error_names_.insert(std::make_pair(move_result::E_NO_UNIT,"move_result::E_NO_UNIT"));
1082  error_names_.insert(std::make_pair(move_result::E_NOT_OWN_UNIT,"move_result::E_NOT_OWN_UNIT"));
1083  error_names_.insert(std::make_pair(move_result::E_INCAPACITATED_UNIT,"move_result::E_INCAPACITATED_UNIT"));
1084  error_names_.insert(std::make_pair(move_result::E_AMBUSHED,"E_AMBUSHED"));
1085  error_names_.insert(std::make_pair(move_result::E_FAILED_TELEPORT,"E_FAILED_TELEPORT"));
1086  error_names_.insert(std::make_pair(move_result::E_NOT_REACHED_DESTINATION,"E_NOT_REACHED_DESTINATION"));
1087  error_names_.insert(std::make_pair(move_result::E_NO_ROUTE,"E_NO_ROUTE"));
1088 
1089  error_names_.insert(std::make_pair(recall_result::E_NOT_AVAILABLE_FOR_RECALLING,"recall_result::E_NOT_AVAILABLE_FOR_RECALLING"));
1090  error_names_.insert(std::make_pair(recall_result::E_NO_GOLD,"recall_result::E_NO_GOLD"));
1091  error_names_.insert(std::make_pair(recall_result::E_NO_LEADER,"recall_result::E_NO_LEADER"));
1092  error_names_.insert(std::make_pair(recall_result::E_LEADER_NOT_ON_KEEP,"recall_result::E_LEADER_NOT_ON_KEEP"));
1093  error_names_.insert(std::make_pair(recall_result::E_BAD_RECALL_LOCATION,"recall_result::E_BAD_RECALL_LOCATION"));
1094 
1095  error_names_.insert(std::make_pair(recruit_result::E_NOT_AVAILABLE_FOR_RECRUITING,"recruit_result::E_NOT_AVAILABLE_FOR_RECRUITING"));
1096  error_names_.insert(std::make_pair(recruit_result::E_UNKNOWN_OR_DUMMY_UNIT_TYPE,"recruit_result::E_UNKNOWN_OR_DUMMY_UNIT_TYPE"));
1097  error_names_.insert(std::make_pair(recruit_result::E_NO_GOLD,"recruit_result::E_NO_GOLD"));
1098  error_names_.insert(std::make_pair(recruit_result::E_NO_LEADER,"recruit_result::E_NO_LEADER"));
1099  error_names_.insert(std::make_pair(recruit_result::E_LEADER_NOT_ON_KEEP,"recruit_result::E_LEADER_NOT_ON_KEEP"));
1100  error_names_.insert(std::make_pair(recruit_result::E_BAD_RECRUIT_LOCATION,"recruit_result::E_BAD_RECRUIT_LOCATION"));
1101 
1102  error_names_.insert(std::make_pair(stopunit_result::E_NO_UNIT,"stopunit_result::E_NO_UNIT"));
1103  error_names_.insert(std::make_pair(stopunit_result::E_NOT_OWN_UNIT,"stopunit_result::E_NOT_OWN_UNIT"));
1104  error_names_.insert(std::make_pair(stopunit_result::E_INCAPACITATED_UNIT,"stopunit_result::E_INCAPACITATED_UNIT"));
1105  }
1107  if (i==error_names_.end()){
1108  ERR_AI_ACTIONS << "error name not available for error #"<<error_code << std::endl;
1109  i = error_names_.find(-1);
1110  assert(i != error_names_.end());
1111  }
1112  return i->second;
1113 }
1114 
1115 std::map<int,std::string> actions::error_names_;
1116 
1117 void sim_gamestate_changed(action_result *result, bool gamestate_changed){
1118  if(gamestate_changed){
1119  result->set_gamestate_changed();
1121  }
1122 }
1123 
1124 } //end of namespace ai
1125 
1126 
1127 std::ostream &operator<<(std::ostream &s, ai::attack_result const &r) {
1128  s << r.do_describe();
1129  return s;
1130 }
1131 
1132 std::ostream &operator<<(std::ostream &s, ai::move_result const &r) {
1133  s << r.do_describe();
1134  return s;
1135 }
1136 
1137 std::ostream &operator<<(std::ostream &s, ai::recall_result const &r) {
1138  s << r.do_describe();
1139  return s;
1140 }
1141 
1142 std::ostream &operator<<(std::ostream &s, ai::recruit_result const &r) {
1143  s << r.do_describe();
1144  return s;
1145 }
1146 
1147 std::ostream &operator<<(std::ostream &s, ai::stopunit_result const &r) {
1148  s << r.do_describe();
1149  return s;
1150 }
1151 
1152 std::ostream &operator<<(std::ostream &s, ai::synced_command_result const &r) {
1153  s << r.do_describe();
1154  return s;
1155 }
static config get_lua_ai(const std::string &lua_code)
bool unreach_is_ok_
Definition: actions.hpp:201
play_controller * controller
Definition: resources.cpp:21
map_location recruit_location_
Definition: actions.hpp:266
map_location recruit_from_
Definition: actions.hpp:267
virtual void do_init_for_execution()
Definition: actions.cpp:926
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator *calc, const size_t width, const size_t height, const teleport_map *teleports, bool border)
virtual void do_check_after()
Definition: actions.cpp:859
bool simulated_synced_command()
::tod_manager * tod_manager
Definition: resources.cpp:31
bool has_ambusher_
Definition: actions.hpp:202
const map_location & get_location() const
Definition: unit.hpp:286
virtual void do_execute()
Definition: actions.cpp:259
void check_before()
Definition: actions.cpp:85
bool remove_movement_
Definition: actions.hpp:198
map_location recall_from_
Definition: actions.hpp:234
unit_const_ptr get_recall_unit(const team &my_team)
Definition: actions.cpp:537
size_t move_unit_and_record(const std::vector< map_location > &steps, undo_list *undo_stack, bool continued_move, bool show_move, bool *interrupted, move_unit_spectator *move_spectator)
Moves a unit across the board.
Definition: move.cpp:1225
static attack_result_ptr execute_attack_action(side_number side, bool execute, const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon, double aggression, const unit_advancements_aspect &advancements=unit_advancements_aspect())
Ask the game to attack an enemy defender using our unit attacker from attackers current location...
Definition: actions.cpp:994
virtual void do_check_before()
Definition: actions.cpp:394
Definition: unit.hpp:95
static std::map< int, std::string > error_names_
Definition: actions.hpp:448
team & get_my_team() const
Definition: actions.cpp:166
No leaders exist.
Definition: create.hpp:41
void do_final_checkup(bool dont_throw=false)
const unit * get_unit()
Definition: actions.cpp:340
virtual void do_execute()=0
static void raise_gamestate_changed()
Notifies all observers of 'ai_gamestate_changed' event.
Definition: manager.cpp:454
map_location unit_location_
Definition: actions.hpp:200
virtual void do_init_for_execution()
Definition: actions.cpp:985
Various functions that implement attacks and attack calculations.
bool is_success() const
Definition: actions.cpp:151
static config get_recall(const std::string &unit_id, const map_location &loc, const map_location &from)
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
const combatant & get_attacker_combatant(const combatant *prev_def=nullptr)
Get the simulation results.
Definition: attack.cpp:410
virtual void do_check_after()
Definition: actions.cpp:411
bool test_route(const unit &un)
Definition: actions.cpp:359
Managing the AI-Game interaction - AI actions and their results.
map_location recall_location_
Definition: actions.hpp:233
static game_info & get_active_ai_info_for_side(side_number side)
Gets AI info for active AI of the given side.
Definition: manager.cpp:765
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
Definition: tod_manager.hpp:56
virtual void do_init_for_execution()
Definition: actions.cpp:520
const map_location & where_
Definition: actions.hpp:265
const std::string & unit_id_
Definition: actions.hpp:231
const unit_type * get_unit_type_known(const std::string &recruit)
Definition: actions.cpp:688
virtual std::string do_describe() const
Definition: actions.cpp:770
virtual void do_init_for_execution()
Definition: actions.cpp:820
virtual std::string do_describe() const
Definition: actions.cpp:246
virtual std::string do_describe() const
Definition: actions.cpp:618
virtual void do_check_before()
Definition: actions.cpp:850
int get_status() const
Definition: actions.cpp:146
unit_type_data unit_types
Definition: types.cpp:1314
Recruitment OK, but not at the specified location.
Definition: create.hpp:45
const unit_advancements_aspect & advancements_
Definition: actions.hpp:164
virtual void do_execute()
Definition: actions.cpp:444
int side() const
Definition: unit.hpp:201
const map_location from_
Definition: actions.hpp:196
void check_victory()
Checks to see if a side has won.
static config unit_name(const unit *u)
Definition: reports.cpp:133
action_result(side_number side)
Definition: actions.cpp:68
bool simulated_attack(const map_location &attacker_loc, const map_location &defender_loc, double attacker_hp, double defender_hp)
virtual void do_check_after()=0
-file sdl_utils.hpp
const std::string & lua_code_
Definition: actions.hpp:310
void init_for_execution()
Definition: actions.cpp:109
void add_synced_command(const std::string &name, const config &command)
Definition: replay.cpp:241
bool has_interrupted_teleport_
Definition: actions.hpp:203
const unit_map::const_iterator & get_failed_teleport() const
get the location of a failed teleport
Definition: move.cpp:78
const combatant & get_defender_combatant(const combatant *prev_def=nullptr)
Definition: attack.cpp:422
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:57
virtual void do_init_for_execution()
Definition: actions.cpp:671
bool incapacitated() const
Definition: unit.hpp:215
int recall_cost() const
Definition: team.hpp:198
static recall_result_ptr execute_recall_action(side_number side, bool execute, const std::string &unit_id, const map_location &where, const map_location &from)
Ask the game to recall a unit for us on specified location.
Definition: actions.cpp:1019
bool simulated_recall(int side, const std::string &unit_id, const map_location &recall_location)
GLuint GLuint end
Definition: glew.h:1221
GLuint64EXT * result
Definition: glew.h:10727
std::ostream & operator<<(std::ostream &s, ai::attack_result const &r)
Definition: actions.cpp:1127
unit_ptr find_if_matches_id(const std::string &unit_id)
Find a unit by id. Null pointer if not found.
static lg::log_domain log_ai_actions("ai/actions")
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.hpp:314
virtual void do_check_after()
Definition: actions.cpp:752
std::vector< team > * teams
Definition: resources.cpp:29
#define ERR_AI_ACTIONS
Definition: actions.cpp:63
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:132
bool valid() const
Definition: location.hpp:69
bool return_value_checked_
Definition: actions.hpp:116
bool is_execution() const
Definition: actions.cpp:156
static void ignore_error_function(const std::string &message, bool heavy)
a function to be passed to run_in_synced_context to ignore the error.
virtual void do_check_after()
Definition: actions.cpp:600
int w() const
Effective map width.
Definition: map.hpp:105
game_board * gameboard
Definition: resources.cpp:20
virtual void do_execute()
Definition: actions.cpp:955
bool location_checked_
Definition: actions.hpp:235
const battle_context_unit_stats & get_defender_stats() const
This method returns the statistics of the defender.
Definition: attack.hpp:163
bool test_enough_gold(const team &my_team, const unit_type &type)
Definition: actions.cpp:698
Computes the statistics of a battle between an attacker and a defender unit.
Definition: attack.hpp:135
synced_command_result(side_number side, const std::string &lua_code, const map_location &location)
Definition: actions.cpp:932
Managing the AIs lifecycle - headers.
int attack_num
Index into unit->attacks() or -1 for none.
Definition: attack.hpp:52
double aggression_
Definition: actions.hpp:163
replay * recorder
Definition: resources.cpp:30
virtual void do_check_after()
Definition: actions.cpp:242
virtual void do_execute()
Definition: actions.cpp:633
static const map_location & null_location()
Definition: location.hpp:195
const bool remove_movement_
Definition: actions.hpp:293
friend void sim_gamestate_changed(action_result *result, bool gamestate_changed)
Definition: actions.cpp:1117
No vacant castle tiles around a leader on a keep.
Definition: create.hpp:44
virtual void do_check_before()=0
int movement_left() const
Returns how far a unit can move this turn (zero if incapacitated).
Definition: unit.hpp:220
virtual void do_init_for_execution()=0
attack_result(side_number side, const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon, double aggression, const unit_advancements_aspect &advancements=unit_advancements_aspect())
Definition: actions.cpp:173
const std::string & unit_name_
Definition: actions.hpp:264
virtual std::string do_describe() const
Definition: actions.cpp:429
void sim_gamestate_changed(action_result *result, bool gamestate_changed)
Definition: actions.cpp:1117
virtual void do_check_before()
Definition: actions.cpp:707
int cost() const
Definition: types.hpp:134
Encapsulates the map of the game.
Definition: location.hpp:38
const bool remove_attacks_
Definition: actions.hpp:294
virtual void do_check_before()
Definition: actions.cpp:555
Various functions related to the creation of units (recruits, recalls, and placed units)...
void maybe_throw_return_to_play_side()
const map_location & defender_loc_
Definition: actions.hpp:161
void check_after()
Definition: actions.cpp:80
RECRUIT_CHECK check_recall_location(const int side, map_location &recall_location, map_location &recall_from, const unit &unit_recall)
Checks if there is a location on which to recall unit_recall.
Definition: create.cpp:276
const unit_map::const_iterator & get_ambusher() const
get the location of an ambusher
Definition: move.cpp:72
int h() const
Effective map height.
Definition: map.hpp:108
No able leaders are on a keep.
Definition: create.hpp:43
virtual std::string do_describe() const
Definition: actions.cpp:946
bool simulated_stopunit(const map_location &unit_location, bool remove_movement, bool remove_attacks)
virtual const map_location & get_unit_location() const
Definition: actions.cpp:406
bool test_enough_gold(const team &my_team)
Definition: actions.cpp:546
int turn() const
std::set< map_location > recent_attacks
hack.
Definition: game_info.hpp:125
void set_gamestate_changed()
Definition: actions.cpp:141
virtual void do_check_before()
Definition: actions.cpp:937
static recruit_result_ptr execute_recruit_action(side_number side, bool execute, const std::string &unit_name, const map_location &where, const map_location &from)
Ask the game to recruit a unit for us on specified location.
Definition: actions.cpp:1030
const unit_map::const_iterator & get_unit() const
get new location of moved unit
Definition: move.cpp:96
size_t i
Definition: function.cpp:1057
stopunit_result(side_number side, const map_location &unit_location, bool remove_movement, bool remove_attacks)
Definition: actions.cpp:826
static synced_command_result_ptr execute_synced_command_action(side_number side, bool execute, const std::string &lua_code, const map_location &location)
Ask the game to run Lua code.
Definition: actions.cpp:1052
bool is_gamestate_changed_
Definition: actions.hpp:127
RECRUIT_CHECK check_recruit_location(const int side, map_location &recruit_location, map_location &recruited_from, const std::string &unit_type)
Checks if there is a location on which to place a recruited unit.
Definition: create.cpp:406
bool simulation_
Definition: resources.cpp:39
virtual std::string do_describe() const
Definition: actions.cpp:876
virtual void do_check_before()
Definition: actions.cpp:177
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
variant a_
Definition: function.cpp:808
const map_location & unit_location_
Definition: actions.hpp:292
static stopunit_result_ptr execute_stopunit_action(side_number side, bool execute, const map_location &unit_location, bool remove_movement, bool remove_attacks)
Ask the game to remove unit movements and/or attack.
Definition: actions.cpp:1041
void set_error(int error_code, bool log_as_error=true)
Definition: actions.cpp:128
boost::shared_ptr< pathfind::plain_route > route_
Definition: actions.hpp:199
virtual const gamemap & map() const
Definition: game_board.hpp:98
#define DBG_AI_ACTIONS
Definition: actions.cpp:60
void set_unit(const unit_map::const_iterator &u)
set the iterator to moved unit
Definition: move.cpp:134
bool is_gamestate_changed() const
Definition: actions.cpp:117
int gold() const
Definition: team.hpp:194
int get_side() const
Definition: actions.hpp:89
static bool run_in_synced_context_if_not_already(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
checks whether we are currently running in a synced context, and if not we enters it...
const map_location to_
Definition: actions.hpp:197
bool find(E event, F functor)
Tests whether an event handler is available.
bool simulated_move(int side, const map_location &from, const map_location &to, int steps, map_location &unit_location)
#define LOG_AI_ACTIONS
Definition: actions.cpp:61
bool simulated_recruit(int side, const unit_type *u, const map_location &recruit_location)
Standard logging facilities (interface).
recall_list_manager & recall_list()
Definition: team.hpp:220
virtual void do_execute()
Definition: actions.cpp:895
virtual std::string do_describe() const =0
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1155
double average_hp(unsigned int healing=0) const
What's the average hp (weighted average of hp_dist).
static config get_recruit(const std::string &type_id, const map_location &loc, const map_location &from)
const battle_context_unit_stats & get_attacker_stats() const
This method returns the statistics of the attacker.
Definition: attack.hpp:160
int side_number
Definition: game_info.hpp:44
unit_iterator find(size_t id)
Definition: map.cpp:285
bool valid() const
Definition: map.hpp:229
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all, bool ignore_units)
Definition: teleport.cpp:233
recall_result(side_number side, const std::string &unit_id, const map_location &where, const map_location &from)
Definition: actions.cpp:526
const map_location where_
Definition: actions.hpp:232
Ensures that the real unit map is active for the duration of the struct's life.
Definition: manager.hpp:279
const unit * get_unit()
Definition: actions.cpp:831
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
static config get_attack(const map_location &a, const map_location &b, int att_weapon, int def_weapon, const std::string &attacker_type_id, const std::string &defender_type_id, int attacker_lvl, int defender_lvl, const size_t turn, const time_of_day &t)
const map_location & attacker_loc_
Definition: actions.hpp:160
GLdouble s
Definition: glew.h:1358
move_result(side_number side, const map_location &from, const map_location &to, bool remove_movement, bool unreach_is_ok)
Definition: actions.cpp:326
static bool is_synced()
GLsizei const GLcharARB ** string
Definition: glew.h:4503
virtual void do_check_after()
Definition: actions.cpp:942
unit_map * units
Definition: resources.cpp:35
recruit_result(side_number side, const std::string &unit_name, const map_location &where, const map_location &from)
Definition: actions.cpp:677
virtual ~action_result()
Definition: actions.cpp:73
static move_result_ptr execute_move_action(side_number side, bool execute, const map_location &from, const map_location &to, bool remove_movement, bool unreach_is_ok=false)
Ask the game to move our unit from location 'from' to location 'to', optionally - doing a partial mov...
Definition: actions.cpp:1007
virtual void do_init_for_execution()
Definition: actions.cpp:320
void attack_unit_and_advance(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display, const ai::unit_advancements_aspect &ai_advancement)
Performs an attack, and advanced the units afterwards.
Definition: attack.cpp:1524
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:115
No leaders able to recall/recruit the given unit/type.
Definition: create.hpp:42
static const std::string & get_error_name(int error_code)
get human-readable name of the error by code.
Definition: actions.cpp:1062
const std::vector< map_location > & route_
Definition: move.cpp:288
const map_location & location_
Definition: actions.hpp:311
virtual void do_execute()
Definition: actions.cpp:785
game_info & get_info() const
Definition: actions.cpp:161
Implement simulated actions.