00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "actions.hpp"
00037 #include "manager.hpp"
00038
00039 #include "../actions.hpp"
00040 #include "../dialogs.hpp"
00041 #include "../game_end_exceptions.hpp"
00042 #include "../game_preferences.hpp"
00043 #include "../log.hpp"
00044 #include "../mouse_handler_base.hpp"
00045 #include "../pathfind/teleport.hpp"
00046 #include "../play_controller.hpp"
00047 #include "../replay.hpp"
00048 #include "../resources.hpp"
00049 #include "../statistics.hpp"
00050 #include "../team.hpp"
00051
00052 namespace ai {
00053
00054 static lg::log_domain log_ai_actions("ai/actions");
00055 #define DBG_AI_ACTIONS LOG_STREAM(debug, log_ai_actions)
00056 #define LOG_AI_ACTIONS LOG_STREAM(info, log_ai_actions)
00057 #define WRN_AI_ACTIONS LOG_STREAM(warn, log_ai_actions)
00058 #define ERR_AI_ACTIONS LOG_STREAM(err, log_ai_actions)
00059
00060
00061
00062
00063 action_result::action_result( side_number side )
00064 : return_value_checked_(true),side_(side),status_(AI_ACTION_SUCCESS),is_execution_(false),is_gamestate_changed_(false)
00065 {
00066 }
00067
00068
00069 action_result::~action_result()
00070 {
00071 if (!return_value_checked_) {
00072 ERR_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs! " << std::endl;
00073 }
00074 }
00075
00076
00077 void action_result::check_after()
00078 {
00079 do_check_after();
00080 }
00081
00082
00083 void action_result::check_before()
00084 {
00085 do_check_before();
00086 }
00087
00088
00089 void action_result::execute()
00090 {
00091 is_execution_ = true;
00092 init_for_execution();
00093 check_before();
00094 if (is_success()){
00095 do_execute();
00096 try {
00097 resources::controller->check_victory();
00098 } catch (...) {
00099 is_ok();
00100 throw;
00101 }
00102 }
00103 if (is_success()){
00104 check_after();
00105 }
00106 is_execution_ = false;
00107 }
00108
00109 void action_result::init_for_execution()
00110 {
00111 return_value_checked_ = false;
00112 is_gamestate_changed_ = false;
00113 status_ = action_result::AI_ACTION_SUCCESS;
00114 do_init_for_execution();
00115 }
00116
00117
00118 bool action_result::is_gamestate_changed() const
00119 {
00120 return is_gamestate_changed_;
00121 }
00122
00123
00124 bool action_result::is_ok()
00125 {
00126 return_value_checked_ = true;
00127 return is_success();
00128 }
00129
00130
00131 void action_result::set_error(int error_code, bool log_as_error){
00132 status_ = error_code;
00133 if (is_execution()) {
00134 if (log_as_error) {
00135 ERR_AI_ACTIONS << "Error #"<<error_code<<" ("<<actions::get_error_name(error_code)<<") in "<< do_describe();
00136 } else {
00137 LOG_AI_ACTIONS << "Error #"<<error_code<<" ("<<actions::get_error_name(error_code)<<") in "<< do_describe();
00138 }
00139 } else {
00140 LOG_AI_ACTIONS << "Error #"<<error_code<<" ("<<actions::get_error_name(error_code)<<") when checking "<< do_describe();
00141 }
00142 }
00143
00144
00145 void action_result::set_gamestate_changed()
00146 {
00147 is_gamestate_changed_ = true;
00148 }
00149
00150
00151 int action_result::get_status() const
00152 {
00153 return status_;
00154 }
00155
00156 bool action_result::is_success() const
00157 {
00158 return (status_ == action_result::AI_ACTION_SUCCESS);
00159 }
00160
00161
00162 bool action_result::is_execution() const
00163 {
00164 return is_execution_;
00165 }
00166
00167
00168 game_info& action_result::get_info() const
00169 {
00170 return manager::get_active_ai_info_for_side(get_side());
00171 }
00172
00173
00174 team& action_result::get_my_team() const
00175 {
00176 return (*resources::teams)[side_-1];
00177 }
00178
00179
00180
00181 attack_result::attack_result( side_number side, const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon, double aggression)
00182 : action_result(side), attacker_loc_(attacker_loc), defender_loc_(defender_loc), attacker_weapon_(attacker_weapon), aggression_(aggression){
00183 }
00184
00185
00186 void attack_result::do_check_before()
00187 {
00188 LOG_AI_ACTIONS << " check_before " << *this << std::endl;
00189 const unit_map::const_iterator attacker = resources::units->find(attacker_loc_);
00190 const unit_map::const_iterator defender = resources::units->find(defender_loc_);
00191
00192 if(attacker==resources::units->end())
00193 {
00194 LOG_AI_ACTIONS << "attempt to attack without attacker\n";
00195 set_error(E_EMPTY_ATTACKER);
00196 return;
00197 }
00198
00199 if (defender==resources::units->end())
00200 {
00201 LOG_AI_ACTIONS << "attempt to attack without defender\n";
00202 set_error(E_EMPTY_DEFENDER);
00203 return;
00204 }
00205
00206 if(attacker->incapacitated()) {
00207 LOG_AI_ACTIONS << "attempt to attack with unit that is petrified\n";
00208 set_error(E_INCAPACITATED_ATTACKER);
00209 return;
00210 }
00211
00212 if(defender->incapacitated()) {
00213 LOG_AI_ACTIONS << "attempt to attack unit that is petrified\n";
00214 set_error(E_INCAPACITATED_DEFENDER);
00215 return;
00216 }
00217
00218 if(!attacker->attacks_left()) {
00219 LOG_AI_ACTIONS << "attempt to attack with no attacks left\n";
00220 set_error(E_NO_ATTACKS_LEFT);
00221 return;
00222 }
00223
00224 if(attacker->side()!=get_side()) {
00225 LOG_AI_ACTIONS << "attempt to attack with not own unit\n";
00226 set_error(E_NOT_OWN_ATTACKER);
00227 return;
00228 }
00229
00230 if(!get_my_team().is_enemy(defender->side())) {
00231 LOG_AI_ACTIONS << "attempt to attack unit that is not enemy\n";
00232 set_error(E_NOT_ENEMY_DEFENDER);
00233 return;
00234 }
00235
00236 if (attacker_weapon_!=-1) {
00237 if ((attacker_weapon_<0)||(attacker_weapon_ >= static_cast<int>(attacker->attacks().size()))) {
00238 LOG_AI_ACTIONS << "invalid weapon selection for the attacker\n";
00239 set_error(E_WRONG_ATTACKER_WEAPON);
00240 return;
00241 }
00242 }
00243
00244 if (!tiles_adjacent(attacker_loc_,defender_loc_)) {
00245 LOG_AI_ACTIONS << "attacker and defender not adjacent\n";
00246 set_error(E_ATTACKER_AND_DEFENDER_NOT_ADJACENT);
00247 return;
00248 }
00249 }
00250
00251
00252 void attack_result::do_check_after()
00253 {
00254 }
00255
00256
00257 std::string attack_result::do_describe() const
00258 {
00259 std::stringstream s;
00260 s << "attack by side ";
00261 s << get_side();
00262 s << " from location "<<attacker_loc_;
00263 s << " to location "<<defender_loc_;
00264 s << " using weapon "<< attacker_weapon_;
00265 s << " with aggression "<< aggression_;
00266 s <<std::endl;
00267 return s.str();
00268 }
00269
00270
00271 void attack_result::do_execute()
00272 {
00273 LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl;
00274
00275 const events::command_disabler disable_commands;
00276
00277 battle_context bc(*resources::units, attacker_loc_,
00278 defender_loc_, attacker_weapon_, -1, aggression_);
00279
00280 int attacker_weapon = bc.get_attacker_stats().attack_num;
00281 int defender_weapon = bc.get_defender_stats().attack_num;
00282
00283 if(attacker_weapon < 0) {
00284 set_error(E_UNABLE_TO_CHOOSE_ATTACKER_WEAPON);
00285 return;
00286 }
00287
00288 const unit_map::const_iterator a_ = resources::units->find(attacker_loc_);
00289 const unit_map::const_iterator d_ = resources::units->find(defender_loc_);
00290
00291
00292 recorder.add_attack(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, a_->type_id(),
00293 d_->type_id(), a_->level(), d_->level(), resources::tod_manager->turn(),
00294 resources::tod_manager->get_time_of_day());
00295 rand_rng::invalidate_seed();
00296 rand_rng::clear_new_seed_callback();
00297 while (!rand_rng::has_valid_seed()) {
00298 manager::raise_user_interact();
00299 manager::raise_sync_network();
00300 SDL_Delay(10);
00301 }
00302 recorder.add_seed("attack", rand_rng::get_last_seed());
00303 attack_unit(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon);
00304 dialogs::advance_unit(attacker_loc_, true);
00305
00306 const unit_map::const_iterator defender = resources::units->find(defender_loc_);
00307 if(defender != resources::units->end()) {
00308 size_t defender_team = defender->side() - 1;
00309 if(defender_team < resources::teams->size()) {
00310 dialogs::advance_unit(defender_loc_ , !(*resources::teams)[defender_team].is_human());
00311 }
00312 }
00313
00314 set_gamestate_changed();
00315
00316
00317 get_info().recent_attacks.insert(defender_loc_);
00318
00319 try {
00320 manager::raise_gamestate_changed();
00321 } catch (...) {
00322 is_ok();
00323 throw;
00324 }
00325 }
00326
00327
00328 void attack_result::do_init_for_execution()
00329 {
00330 }
00331
00332
00333
00334
00335
00336 move_result::move_result(side_number side, const map_location& from,
00337 const map_location& to, bool remove_movement, bool unreach_is_ok)
00338 : action_result(side)
00339 , from_(from)
00340 , move_spectator_(*resources::units)
00341 , to_(to)
00342 , remove_movement_(remove_movement)
00343 , route_()
00344 , unit_location_(from)
00345 , unreach_is_ok_(unreach_is_ok)
00346 {
00347 }
00348
00349
00350 const unit *move_result::get_unit()
00351 {
00352 unit_map::const_iterator un = resources::units->find(from_);
00353 if (un==resources::units->end()){
00354 set_error(E_NO_UNIT);
00355 return NULL;
00356 }
00357 const unit *u = &*un;
00358 if (u->side() != get_side()) {
00359 set_error(E_NOT_OWN_UNIT);
00360 return NULL;
00361 }
00362 if (u->incapacitated()) {
00363 set_error(E_INCAPACITATED_UNIT);
00364 return NULL;
00365 }
00366 return u;
00367 }
00368
00369
00370 bool move_result::test_route(const unit &un)
00371 {
00372 if (from_== to_) {
00373 if (!remove_movement_ || (un.movement_left() == 0) ) {
00374 set_error(E_EMPTY_MOVE);
00375 return false;
00376 }
00377 return true;
00378 }
00379
00380 if (un.movement_left() == 0 ) {
00381 set_error(E_EMPTY_MOVE);
00382 return false;
00383 }
00384
00385 if (!to_.valid()) {
00386 set_error(E_NO_ROUTE);
00387 return false;
00388 }
00389
00390 team &my_team = get_my_team();
00391 const pathfind::shortest_path_calculator calc(un, my_team, *resources::units, *resources::teams, *resources::game_map);
00392
00393
00394 pathfind::teleport_map allowed_teleports = pathfind::get_teleport_locations(un, my_team, true);
00395
00396
00397 route_ = boost::shared_ptr<pathfind::plain_route>( new pathfind::plain_route(pathfind::a_star_search(un.get_location(), to_, 10000.0, &calc, resources::game_map->w(), resources::game_map->h(), &allowed_teleports)));
00398 if (route_->steps.empty()) {
00399 set_error(E_NO_ROUTE);
00400 return false;
00401 }
00402 return true;
00403 }
00404
00405 void move_result::do_check_before()
00406 {
00407 LOG_AI_ACTIONS << " check_before " << *this << std::endl;
00408 const unit *u = get_unit();
00409 if (!u) {
00410 return;
00411 }
00412 if (!test_route(*u)) {
00413 return;
00414 }
00415 }
00416
00417
00418 const map_location& move_result::get_unit_location() const
00419 {
00420 return unit_location_;
00421 }
00422
00423
00424 void move_result::do_check_after()
00425 {
00426 if (move_spectator_.get_ambusher().valid()) {
00427 set_error(E_AMBUSHED,false);
00428 return;
00429 }
00430 if (move_spectator_.get_failed_teleport().valid()) {
00431 set_error(E_FAILED_TELEPORT);
00432 return;
00433 }
00434
00435
00436 if (!unreach_is_ok_ && unit_location_!=to_) {
00437 set_error(E_NOT_REACHED_DESTINATION);
00438 return;
00439 }
00440 }
00441
00442
00443 std::string move_result::do_describe() const
00444 {
00445 std::stringstream s;
00446 if (remove_movement_){
00447 s << "full move by side ";
00448 } else {
00449 s << "partial move by side ";
00450 }
00451 s << get_side();
00452 s << " from location "<<from_;
00453 s << " to location "<<to_;
00454 s <<std::endl;
00455 return s.str();
00456 }
00457
00458
00459 void move_result::do_execute()
00460 {
00461 LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl;
00462 assert(is_success());
00463
00464 move_spectator_.set_unit(resources::units->find(from_));
00465
00466 if (from_ != to_) {
00467 move_unit(
00468 &move_spectator_,
00469 route_->steps,
00470 &recorder,
00471 NULL,
00472 preferences::show_ai_moves(),
00473 NULL,
00474 true,
00475 true,
00476 false);
00477
00478 if ( move_spectator_.get_ambusher().valid() || !move_spectator_.get_seen_enemies().empty() || !move_spectator_.get_seen_friends().empty() ) {
00479 set_gamestate_changed();
00480 } else if (move_spectator_.get_unit().valid()){
00481 unit_location_ = move_spectator_.get_unit()->get_location();
00482 if (unit_location_ != from_) {
00483 set_gamestate_changed();
00484 }
00485 }
00486 } else {
00487 assert(remove_movement_);
00488 }
00489
00490 if (move_spectator_.get_unit().valid()){
00491 unit_location_ = move_spectator_.get_unit()->get_location();
00492 if (remove_movement_ && move_spectator_.get_unit()->movement_left() > 0 && unit_location_ == to_)
00493 {
00494 stopunit_result_ptr stopunit_res = actions::execute_stopunit_action(get_side(),true,unit_location_,true,false);
00495 if (!stopunit_res->is_ok()) {
00496 set_error(stopunit_res->get_status());
00497 }
00498 if (stopunit_res->is_gamestate_changed()) {
00499 set_gamestate_changed();
00500 }
00501 }
00502 } else {
00503 unit_location_ = map_location();
00504 }
00505
00506 if (is_gamestate_changed()) {
00507 try {
00508 manager::raise_gamestate_changed();
00509 } catch (...) {
00510 is_ok();
00511 throw;
00512 }
00513 }
00514 }
00515
00516
00517 void move_result::do_init_for_execution()
00518 {
00519 move_spectator_.reset(*resources::units);
00520 }
00521
00522
00523
00524
00525 recall_result::recall_result(side_number side,
00526 const std::string& unit_id, const map_location& where, const map_location& from)
00527 : action_result(side)
00528 , unit_id_(unit_id)
00529 , where_(where)
00530 , recall_location_(where)
00531 , recall_from_(from)
00532 {
00533 }
00534
00535 bool recall_result::test_available_for_recalling(const team &my_team)
00536 {
00537 const std::vector<unit>::const_iterator rec = find_if_matches_id(my_team.recall_list(), unit_id_);
00538 if (rec == my_team.recall_list().end()) {
00539 set_error(E_NOT_AVAILABLE_FOR_RECALLING);
00540 return false;
00541 }
00542 return true;
00543 }
00544
00545
00546 bool recall_result::test_enough_gold(const team &my_team)
00547 {
00548 if (my_team.gold() < my_team.recall_cost() ) {
00549 set_error(E_NO_GOLD);
00550 return false;
00551 }
00552 return true;
00553 }
00554
00555 const unit *recall_result::get_leader()
00556 {
00557 unit_map::const_iterator my_leader = resources::units->find_leader(get_side());
00558 if (my_leader == resources::units->end()){
00559 set_error(E_NO_LEADER);
00560 return NULL;
00561 }
00562 return &*my_leader;
00563
00564 }
00565
00566 bool recall_result::test_leader_on_keep(const unit &my_leader)
00567 {
00568 if (!resources::game_map->is_keep(my_leader.get_location())) {
00569 set_error(E_LEADER_NOT_ON_KEEP);
00570 return false;
00571 }
00572 return true;
00573 }
00574
00575 bool recall_result::test_suitable_recall_location(const unit &my_leader)
00576 {
00577 recall_location_ = where_;
00578
00579
00580 if (!resources::game_map->on_board(recall_location_)) {
00581 recall_location_ = pathfind::find_vacant_tile(*resources::game_map, *resources::units, my_leader.get_location(), pathfind::VACANT_CASTLE);
00582 }
00583
00584 if (!can_recruit_on(*resources::game_map, my_leader.get_location(), recall_location_)) {
00585 set_error(E_BAD_RECALL_LOCATION);
00586 return false;
00587 }
00588 return true;
00589 }
00590
00591 void recall_result::do_check_before()
00592 {
00593 LOG_AI_ACTIONS << " check_before " << *this << std::endl;
00594 const team& my_team = get_my_team();
00595
00596
00597 if ( !test_available_for_recalling(my_team)) {
00598 return;
00599 }
00600
00601
00602 if (!test_enough_gold(my_team)) {
00603 return;
00604 }
00605
00606
00607 const unit *my_leader = get_leader();
00608
00609 if (!my_leader) {
00610 return;
00611 }
00612
00613
00614 if (!test_leader_on_keep(*my_leader)) {
00615 return;
00616 }
00617
00618
00619 if (!test_suitable_recall_location(*my_leader)) {
00620 return;
00621 }
00622
00623 }
00624
00625
00626 void recall_result::do_check_after()
00627 {
00628 if (!resources::game_map->on_board(recall_location_)){
00629 set_error(AI_ACTION_FAILURE);
00630 return;
00631 }
00632
00633 unit_map::const_iterator unit = resources::units->find(recall_location_);
00634 if (unit==resources::units->end()){
00635 set_error(AI_ACTION_FAILURE);
00636 return;
00637 }
00638 if (unit->side() != get_side()){
00639 set_error(AI_ACTION_FAILURE);
00640 return;
00641 }
00642
00643 }
00644
00645 std::string recall_result::do_describe() const
00646 {
00647 std::stringstream s;
00648 s << "recall by side ";
00649 s << get_side();
00650 s << " of unit id ["<<unit_id_;
00651 if (where_ != map_location::null_location){
00652 s << "] on location "<<where_;
00653 } else {
00654 s << "] on any suitable location";
00655 }
00656 s <<std::endl;
00657 return s.str();
00658 }
00659
00660
00661 void recall_result::do_execute()
00662 {
00663 LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl;
00664 assert(is_success());
00665
00666 team& my_team = get_my_team();
00667
00668 const events::command_disabler disable_commands;
00669
00670 std::vector<unit>::iterator rec = find_if_matches_id(my_team.recall_list(), unit_id_);
00671
00672 assert(rec != my_team.recall_list().end());
00673
00674 const std::string &err = find_recall_location(get_side(), recall_location_, recall_from_, *rec);
00675 if(!err.empty()) {
00676 set_error(AI_ACTION_FAILURE);
00677 return;
00678 } else {
00679
00680 unit &un = *rec;
00681 recorder.add_recall(un.id(), recall_location_, recall_from_);
00682 place_recruit(un, recall_location_, recall_from_, true, true);
00683 statistics::recall_unit(un);
00684 my_team.spend_gold(my_team.recall_cost());
00685
00686 my_team.recall_list().erase(rec);
00687 if (resources::screen!=NULL) {
00688 resources::screen->invalidate_game_status();
00689 resources::screen->invalidate_all();
00690 }
00691 recorder.add_checksum_check(recall_location_);
00692 set_gamestate_changed();
00693 try {
00694 manager::raise_gamestate_changed();
00695 } catch (...) {
00696 is_ok();
00697 throw;
00698 }
00699 }
00700
00701 }
00702
00703
00704 void recall_result::do_init_for_execution()
00705 {
00706 }
00707
00708
00709
00710
00711
00712 recruit_result::recruit_result(side_number side,
00713 const std::string& unit_name, const map_location& where, const map_location& from)
00714 : action_result(side)
00715 , unit_name_(unit_name)
00716 , where_(where)
00717 , recruit_location_(where)
00718 , recruit_from_(from)
00719 , num_(0)
00720 {
00721 }
00722
00723 const std::string &recruit_result::get_available_for_recruiting(const team &my_team)
00724 {
00725 const std::set<std::string> &recruit_set = my_team.recruits();
00726 std::set<std::string>::const_iterator recruit = recruit_set.find(unit_name_);
00727 if (recruit == recruit_set.end()) {
00728 set_error(E_NOT_AVAILABLE_FOR_RECRUITING);
00729 static std::string dummy;
00730 return dummy;
00731 }
00732 num_ = std::distance(recruit_set.begin(),recruit);
00733 return *recruit;
00734 }
00735
00736 const unit_type *recruit_result::get_unit_type_known(const std::string &recruit)
00737 {
00738 const unit_type *type = unit_types.find(recruit);
00739 if (!type) {
00740 set_error(E_UNKNOWN_OR_DUMMY_UNIT_TYPE);
00741 return NULL;
00742 }
00743 return type;
00744 }
00745
00746 bool recruit_result::test_enough_gold(const team &my_team, const unit_type &type)
00747 {
00748 if (my_team.gold() < type.cost()) {
00749 set_error(E_NO_GOLD);
00750 return false;
00751 }
00752 return true;
00753 }
00754
00755 const unit *recruit_result::get_leader()
00756 {
00757 unit_map::const_iterator my_leader = resources::units->find_leader(get_side());
00758 if (my_leader == resources::units->end()){
00759 set_error(E_NO_LEADER);
00760 return NULL;
00761 }
00762 return &*my_leader;
00763
00764 }
00765
00766 bool recruit_result::test_leader_on_keep(const unit &my_leader)
00767 {
00768 if (!resources::game_map->is_keep(my_leader.get_location())) {
00769 set_error(E_LEADER_NOT_ON_KEEP);
00770 return false;
00771 }
00772 return true;
00773 }
00774
00775 bool recruit_result::test_suitable_recruit_location(const unit &my_leader)
00776 {
00777 recruit_location_ = where_;
00778
00779
00780 if (!resources::game_map->on_board(recruit_location_)) {
00781 recruit_location_ = pathfind::find_vacant_tile(*resources::game_map, *resources::units, my_leader.get_location(), pathfind::VACANT_CASTLE);
00782 }
00783
00784 if (!can_recruit_on(*resources::game_map, my_leader.get_location(), recruit_location_)) {
00785 set_error(E_BAD_RECRUIT_LOCATION);
00786 return false;
00787 }
00788 return true;
00789 }
00790
00791 void recruit_result::do_check_before()
00792 {
00793 LOG_AI_ACTIONS << " check_before " << *this << std::endl;
00794
00795 const team& my_team = get_my_team();
00796
00797
00798 const std::string &s_recruit = get_available_for_recruiting(my_team);
00799
00800 if (s_recruit.empty()) {
00801 return;
00802 }
00803
00804
00805 const unit_type *s_type = get_unit_type_known(s_recruit);
00806 if (!s_type) {
00807 return;
00808 }
00809
00810
00811 if (!test_enough_gold(my_team, *s_type)) {
00812 return;
00813 }
00814
00815
00816 const unit *my_leader = get_leader();
00817
00818 if (!my_leader ) {
00819 return;
00820 }
00821
00822
00823
00824 if (!test_leader_on_keep(*my_leader)) {
00825 return;
00826 }
00827
00828
00829 if (!test_suitable_recruit_location(*my_leader)) {
00830 return;
00831 }
00832
00833 }
00834
00835
00836 void recruit_result::do_check_after()
00837 {
00838 if (!resources::game_map->on_board(recruit_location_)) {
00839 set_error(AI_ACTION_FAILURE);
00840 return;
00841 }
00842
00843 unit_map::const_iterator unit = resources::units->find(recruit_location_);
00844 if (unit==resources::units->end()) {
00845 set_error(AI_ACTION_FAILURE);
00846 return;
00847 }
00848 if (unit->side() != get_side()) {
00849 set_error(AI_ACTION_FAILURE);
00850 return;
00851 }
00852
00853 }
00854
00855 std::string recruit_result::do_describe() const
00856 {
00857 std::stringstream s;
00858 s << "recruitment by side ";
00859 s << get_side();
00860 s << " of unit type ["<<unit_name_;
00861 if (where_ != map_location::null_location){
00862 s << "] on location "<<where_;
00863 } else {
00864 s << "] on any suitable location";
00865 }
00866 s <<std::endl;
00867 return s.str();
00868 }
00869
00870
00871 void recruit_result::do_execute()
00872 {
00873 LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl;
00874 assert(is_success());
00875
00876
00877
00878
00879
00880
00881
00882 recorder.add_recruit(num_,recruit_location_,recruit_from_);
00883 replay_undo replay_guard(recorder);
00884 const unit_type *u = unit_types.find(unit_name_);
00885 const events::command_disabler disable_commands;
00886 const std::string recruit_err = find_recruit_location(get_side(), recruit_location_, recruit_from_, u->id());
00887 if(recruit_err.empty()) {
00888 const unit new_unit(u, get_side(), true);
00889 place_recruit(new_unit, recruit_location_, recruit_from_, false, preferences::show_ai_moves());
00890 statistics::recruit_unit(new_unit);
00891 get_my_team().spend_gold(u->cost());
00892
00893 replay_guard.confirm_transaction();
00894 set_gamestate_changed();
00895 try {
00896 manager::raise_gamestate_changed();
00897 } catch (...) {
00898 is_ok();
00899 throw;
00900 }
00901 } else {
00902 set_error(AI_ACTION_FAILURE);
00903 }
00904
00905 }
00906
00907
00908 void recruit_result::do_init_for_execution()
00909 {
00910 }
00911
00912
00913
00914
00915
00916
00917 stopunit_result::stopunit_result( side_number side, const map_location& unit_location, bool remove_movement, bool remove_attacks)
00918 : action_result(side), unit_location_(unit_location), remove_movement_(remove_movement), remove_attacks_(remove_attacks)
00919 {
00920 }
00921
00922 const unit *stopunit_result::get_unit()
00923 {
00924 unit_map::const_iterator un = resources::units->find(unit_location_);
00925 if (un==resources::units->end()){
00926 set_error(E_NO_UNIT);
00927 return NULL;
00928 }
00929 const unit *u = &*un;
00930 if (u->side() != get_side()) {
00931 set_error(E_NOT_OWN_UNIT);
00932 return NULL;
00933 }
00934 if (u->incapacitated()) {
00935 set_error(E_INCAPACITATED_UNIT);
00936 return NULL;
00937 }
00938 return u;
00939 }
00940
00941 void stopunit_result::do_check_before()
00942 {
00943 LOG_AI_ACTIONS << " check_before " << *this << std::endl;
00944
00945 if (!get_unit()) {
00946 return;
00947 }
00948
00949 }
00950
00951
00952 void stopunit_result::do_check_after()
00953 {
00954 unit_map::const_iterator un = resources::units->find(unit_location_);
00955 if (un==resources::units->end()){
00956 set_error(AI_ACTION_FAILURE);
00957 return;
00958 }
00959 if (remove_movement_ && un->movement_left() != 0) {
00960 set_error(AI_ACTION_FAILURE);
00961 return;
00962 }
00963 if (remove_attacks_ && un->attacks_left() != 0) {
00964 set_error(AI_ACTION_FAILURE);
00965 return;
00966 }
00967 }
00968
00969 std::string stopunit_result::do_describe() const
00970 {
00971 std::stringstream s;
00972 s <<" stopunit by side ";
00973 s << get_side();
00974 if (remove_movement_){
00975 s << " : remove movement ";
00976 }
00977 if (remove_movement_ && remove_attacks_){
00978 s << "and ";
00979 }
00980 if (remove_attacks_){
00981 s << " remove attacks ";
00982 }
00983 s << "from unit on location "<<unit_location_;
00984 s <<std::endl;
00985 return s.str();
00986 }
00987
00988 void stopunit_result::do_execute()
00989 {
00990 LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl;
00991 assert(is_success());
00992 unit_map::iterator un = resources::units->find(unit_location_);
00993 try {
00994 if (remove_movement_){
00995 un->remove_movement_ai();
00996 set_gamestate_changed();
00997 manager::raise_gamestate_changed();
00998 }
00999 if (remove_attacks_){
01000 un->remove_attacks_ai();
01001 set_gamestate_changed();
01002 manager::raise_gamestate_changed();
01003 }
01004 } catch (...) {
01005 is_ok();
01006 throw;
01007 }
01008 }
01009
01010
01011 void stopunit_result::do_init_for_execution()
01012 {
01013 }
01014
01015
01016
01017
01018
01019
01020
01021
01022 attack_result_ptr actions::execute_attack_action( side_number side,
01023 bool execute,
01024 const map_location& attacker_loc,
01025 const map_location& defender_loc,
01026 int attacker_weapon,
01027 double aggression)
01028 {
01029 attack_result_ptr action(new attack_result(side,attacker_loc,defender_loc,attacker_weapon,aggression));
01030 execute ? action->execute() : action->check_before();
01031 return action;
01032 }
01033
01034
01035
01036 move_result_ptr actions::execute_move_action( side_number side,
01037 bool execute,
01038 const map_location& from,
01039 const map_location& to,
01040 bool remove_movement,
01041 bool unreach_is_ok)
01042 {
01043 move_result_ptr action(new move_result(side,from,to,remove_movement,unreach_is_ok));
01044 execute ? action->execute() : action->check_before();
01045 return action;
01046
01047 }
01048
01049
01050 recall_result_ptr actions::execute_recall_action( side_number side,
01051 bool execute,
01052 const std::string& unit_id,
01053 const map_location& where,
01054 const map_location& from)
01055 {
01056 recall_result_ptr action(new recall_result(side,unit_id,where,from));
01057 execute ? action->execute() : action->check_before();
01058 return action;
01059
01060 }
01061
01062
01063 recruit_result_ptr actions::execute_recruit_action( side_number side,
01064 bool execute,
01065 const std::string& unit_name,
01066 const map_location& where,
01067 const map_location& from)
01068 {
01069 recruit_result_ptr action(new recruit_result(side,unit_name,where,from));
01070 execute ? action->execute() : action->check_before();
01071 return action;
01072
01073 }
01074
01075
01076 stopunit_result_ptr actions::execute_stopunit_action( side_number side,
01077 bool execute,
01078 const map_location& unit_location,
01079 bool remove_movement,
01080 bool remove_attacks)
01081 {
01082 stopunit_result_ptr action(new stopunit_result(side,unit_location,remove_movement,remove_attacks));
01083 execute ? action->execute() : action->check_before();
01084 return action;
01085
01086 }
01087
01088
01089 const std::string& actions::get_error_name(int error_code)
01090 {
01091 if (error_names_.empty()){
01092 error_names_.insert(std::make_pair(action_result::AI_ACTION_SUCCESS,"action_result::AI_ACTION_SUCCESS"));
01093 error_names_.insert(std::make_pair(action_result::AI_ACTION_STARTED,"action_result::AI_ACTION_STARTED"));
01094 error_names_.insert(std::make_pair(action_result::AI_ACTION_FAILURE,"action_result::AI_ACTION_FAILURE"));
01095
01096 error_names_.insert(std::make_pair(attack_result::E_EMPTY_ATTACKER,"attack_result::E_EMPTY_ATTACKER"));
01097 error_names_.insert(std::make_pair(attack_result::E_EMPTY_DEFENDER,"attack_result::E_EMPTY_DEFENDER"));
01098 error_names_.insert(std::make_pair(attack_result::E_INCAPACITATED_ATTACKER,"attack_result::E_INCAPACITATED_ATTACKER"));
01099 error_names_.insert(std::make_pair(attack_result::E_INCAPACITATED_DEFENDER,"attack_result::E_INCAPACITATED_DEFENDER"));
01100 error_names_.insert(std::make_pair(attack_result::E_NOT_OWN_ATTACKER,"attack_result::E_NOT_OWN_ATTACKER"));
01101 error_names_.insert(std::make_pair(attack_result::E_NOT_ENEMY_DEFENDER,"attack_result::E_NOT_ENEMY_DEFENDER"));
01102 error_names_.insert(std::make_pair(attack_result::E_NO_ATTACKS_LEFT,"attack_result::E_NO_ATTACKS_LEFT"));
01103 error_names_.insert(std::make_pair(attack_result::E_WRONG_ATTACKER_WEAPON,"attack_result::E_WRONG_ATTACKER_WEAPON"));
01104 error_names_.insert(std::make_pair(attack_result::E_UNABLE_TO_CHOOSE_ATTACKER_WEAPON,"attack_result::E_UNABLE_TO_CHOOSE_ATTACKER_WEAPON"));
01105 error_names_.insert(std::make_pair(attack_result::E_ATTACKER_AND_DEFENDER_NOT_ADJACENT,"attack_result::E_ATTACKER_AND_DEFENDER_NOT_ADJACENT"));
01106
01107 error_names_.insert(std::make_pair(move_result::E_EMPTY_MOVE,"move_result::E_EMPTY_MOVE"));
01108 error_names_.insert(std::make_pair(move_result::E_NO_UNIT,"move_result::E_NO_UNIT"));
01109 error_names_.insert(std::make_pair(move_result::E_NOT_OWN_UNIT,"move_result::E_NOT_OWN_UNIT"));
01110 error_names_.insert(std::make_pair(move_result::E_INCAPACITATED_UNIT,"move_result::E_INCAPACITATED_UNIT"));
01111 error_names_.insert(std::make_pair(move_result::E_AMBUSHED,"E_AMBUSHED"));
01112 error_names_.insert(std::make_pair(move_result::E_FAILED_TELEPORT,"E_FAILED_TELEPORT"));
01113 error_names_.insert(std::make_pair(move_result::E_NOT_REACHED_DESTINATION,"E_NOT_REACHED_DESTINATION"));
01114 error_names_.insert(std::make_pair(move_result::E_NO_ROUTE,"E_NO_ROUTE"));
01115
01116 error_names_.insert(std::make_pair(recall_result::E_NOT_AVAILABLE_FOR_RECALLING,"recall_result::E_NOT_AVAILABLE_FOR_RECALLING"));
01117 error_names_.insert(std::make_pair(recall_result::E_NO_GOLD,"recall_result::E_NO_GOLD"));
01118 error_names_.insert(std::make_pair(recall_result::E_NO_LEADER,"recall_result::E_NO_LEADER"));
01119 error_names_.insert(std::make_pair(recall_result::E_LEADER_NOT_ON_KEEP,"recall_result::E_LEADER_NOT_ON_KEEP"));
01120 error_names_.insert(std::make_pair(recall_result::E_BAD_RECALL_LOCATION,"recall_result::E_BAD_RECALL_LOCATION"));
01121
01122 error_names_.insert(std::make_pair(recruit_result::E_NOT_AVAILABLE_FOR_RECRUITING,"recruit_result::E_NOT_AVAILABLE_FOR_RECRUITING"));
01123 error_names_.insert(std::make_pair(recruit_result::E_UNKNOWN_OR_DUMMY_UNIT_TYPE,"recruit_result::E_UNKNOWN_OR_DUMMY_UNIT_TYPE"));
01124 error_names_.insert(std::make_pair(recruit_result::E_NO_GOLD,"recruit_result::E_NO_GOLD"));
01125 error_names_.insert(std::make_pair(recruit_result::E_NO_LEADER,"recruit_result::E_NO_LEADER"));
01126 error_names_.insert(std::make_pair(recruit_result::E_LEADER_NOT_ON_KEEP,"recruit_result::E_LEADER_NOT_ON_KEEP"));
01127 error_names_.insert(std::make_pair(recruit_result::E_BAD_RECRUIT_LOCATION,"recruit_result::E_BAD_RECRUIT_LOCATION"));
01128
01129 error_names_.insert(std::make_pair(stopunit_result::E_NO_UNIT,"stopunit_result::E_NO_UNIT"));
01130 error_names_.insert(std::make_pair(stopunit_result::E_NOT_OWN_UNIT,"stopunit_result::E_NOT_OWN_UNIT"));
01131 error_names_.insert(std::make_pair(stopunit_result::E_INCAPACITATED_UNIT,"stopunit_result::E_INCAPACITATED_UNIT"));
01132 }
01133 std::map<int,std::string>::iterator i = error_names_.find(error_code);
01134 if (i==error_names_.end()){
01135 ERR_AI_ACTIONS << "error name not available for error #"<<error_code << std::endl;
01136 i = error_names_.find(-1);
01137 assert(i != error_names_.end());
01138 }
01139 return i->second;
01140 }
01141
01142
01143 std::map<int,std::string> actions::error_names_;
01144
01145 }
01146
01147
01148 std::ostream &operator<<(std::ostream &s, ai::attack_result const &r) {
01149 s << r.do_describe();
01150 return s;
01151 }
01152
01153
01154 std::ostream &operator<<(std::ostream &s, ai::move_result const &r) {
01155 s << r.do_describe();
01156 return s;
01157 }
01158
01159
01160 std::ostream &operator<<(std::ostream &s, ai::recall_result const &r) {
01161 s << r.do_describe();
01162 return s;
01163 }
01164
01165
01166 std::ostream &operator<<(std::ostream &s, ai::recruit_result const &r) {
01167 s << r.do_describe();
01168 return s;
01169 }
01170
01171
01172 std::ostream &operator<<(std::ostream &s, ai::stopunit_result const &r) {
01173 s << r.do_describe();
01174 return s;
01175 }