00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "actions.hpp"
00023 #include "contexts.hpp"
00024 #include "manager.hpp"
00025
00026 #include "composite/aspect.hpp"
00027 #include "composite/engine.hpp"
00028 #include "composite/goal.hpp"
00029
00030 #include "default/ai.hpp"
00031
00032 #include "../callable_objects.hpp"
00033 #include "../formula.hpp"
00034 #include "../formula_callable.hpp"
00035 #include "../formula_function.hpp"
00036 #include "../formula_fwd.hpp"
00037 #include "../game_display.hpp"
00038 #include "../game_events.hpp"
00039 #include "../log.hpp"
00040 #include "../mouse_handler_base.hpp"
00041 #include "../resources.hpp"
00042 #include "../tod_manager.hpp"
00043
00044 static lg::log_domain log_ai("ai/general");
00045 #define DBG_AI LOG_STREAM(debug, log_ai)
00046 #define LOG_AI LOG_STREAM(info, log_ai)
00047 #define WRN_AI LOG_STREAM(warn, log_ai)
00048 #define ERR_AI LOG_STREAM(err, log_ai)
00049
00050
00051
00052
00053 namespace ai {
00054
00055 int side_context_impl::get_recursion_count() const
00056 {
00057 return recursion_counter_.get_count();
00058 }
00059
00060
00061 int readonly_context_impl::get_recursion_count() const
00062 {
00063 return recursion_counter_.get_count();
00064 }
00065
00066
00067 int readwrite_context_impl::get_recursion_count() const
00068 {
00069 return recursion_counter_.get_count();
00070 }
00071
00072
00073 void readonly_context_impl::raise_user_interact() const
00074 {
00075 manager::raise_user_interact();
00076 }
00077
00078
00079 void readwrite_context_impl::raise_gamestate_changed() const
00080 {
00081 manager::raise_gamestate_changed();
00082 }
00083
00084
00085 team& readwrite_context_impl::current_team_w()
00086 {
00087 return (*resources::teams)[get_side()-1];
00088 }
00089
00090 attack_result_ptr readwrite_context_impl::execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
00091 unit_map::iterator i = resources::units->find(attacker_loc);
00092 double m_aggression = i.valid() && i->can_recruit() ? get_leader_aggression() : get_aggression();
00093 return actions::execute_attack_action(get_side(),true,attacker_loc,defender_loc,attacker_weapon, m_aggression);
00094 }
00095
00096
00097 attack_result_ptr readonly_context_impl::check_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
00098 unit_map::iterator i = resources::units->find(attacker_loc);
00099 double m_aggression = i.valid() && i->can_recruit() ? get_leader_aggression() : get_aggression();
00100 return actions::execute_attack_action(get_side(),false,attacker_loc,defender_loc,attacker_weapon, m_aggression);
00101 }
00102
00103
00104 move_result_ptr readwrite_context_impl::execute_move_action(const map_location& from, const map_location& to, bool remove_movement){
00105 return actions::execute_move_action(get_side(),true,from,to,remove_movement);
00106 }
00107
00108
00109 move_result_ptr readonly_context_impl::check_move_action(const map_location& from, const map_location& to, bool remove_movement){
00110 return actions::execute_move_action(get_side(),false,from,to,remove_movement);
00111 }
00112
00113
00114 recall_result_ptr readwrite_context_impl::execute_recall_action(const std::string& id, const map_location &where, const map_location &from){
00115 return actions::execute_recall_action(get_side(),true,id,where,from);
00116 }
00117
00118
00119 recruit_result_ptr readwrite_context_impl::execute_recruit_action(const std::string& unit_name, const map_location &where, const map_location &from){
00120 return actions::execute_recruit_action(get_side(),true,unit_name,where,from);
00121 }
00122
00123
00124 recall_result_ptr readonly_context_impl::check_recall_action(const std::string& id, const map_location &where, const map_location &from){
00125 return actions::execute_recall_action(get_side(),false,id,where,from);
00126 }
00127
00128
00129 recruit_result_ptr readonly_context_impl::check_recruit_action(const std::string& unit_name, const map_location &where, const map_location &from){
00130 return actions::execute_recruit_action(get_side(),false,unit_name,where,from);
00131 }
00132
00133
00134 stopunit_result_ptr readwrite_context_impl::execute_stopunit_action(const map_location& unit_location, bool remove_movement, bool remove_attacks){
00135 return actions::execute_stopunit_action(get_side(),true,unit_location,remove_movement,remove_attacks);
00136 }
00137
00138
00139 stopunit_result_ptr readonly_context_impl::check_stopunit_action(const map_location& unit_location, bool remove_movement, bool remove_attacks){
00140 return actions::execute_stopunit_action(get_side(),false,unit_location,remove_movement,remove_attacks);
00141 }
00142
00143
00144 template<typename T>
00145 void readonly_context_impl::add_known_aspect(const std::string &name, boost::shared_ptr< typesafe_aspect <T> > &where)
00146 {
00147 boost::shared_ptr< typesafe_known_aspect <T> > ka_ptr(new typesafe_known_aspect<T>(name,where,aspects_));
00148 known_aspects_.insert(make_pair(name,ka_ptr));
00149 }
00150
00151 readonly_context_impl::readonly_context_impl(side_context &context, const config &cfg)
00152 : cfg_(cfg),
00153 engines_(),
00154 known_aspects_(),
00155 aggression_(),
00156 attack_depth_(),
00157 aspects_(),
00158 attacks_(),
00159 avoid_(),
00160 caution_(),
00161 defensive_position_cache_(),
00162 dstsrc_(),enemy_dstsrc_(),
00163 enemy_possible_moves_(),
00164 enemy_srcdst_(),
00165 grouping_(),
00166 goals_(),
00167 keeps_(),
00168 leader_aggression_(),
00169 leader_goal_(),
00170 leader_value_(),
00171 move_maps_enemy_valid_(false),
00172 move_maps_valid_(false),
00173 dst_src_valid_lua_(false),
00174 dst_src_enemy_valid_lua_(false),
00175 src_dst_valid_lua_(false),
00176 src_dst_enemy_valid_lua_(false),
00177 number_of_possible_recruits_to_force_recruit_(),
00178 passive_leader_(),
00179 passive_leader_shares_keep_(),
00180 possible_moves_(),
00181 recruitment_(),
00182 recruitment_ignore_bad_combat_(),
00183 recruitment_ignore_bad_movement_(),
00184 recruitment_pattern_(),
00185 recursion_counter_(context.get_recursion_count()),
00186 scout_village_targeting_(),
00187 simple_targeting_(),
00188 srcdst_(),
00189 support_villages_(),
00190 unit_stats_cache_(),
00191 village_value_(),
00192 villages_per_scout_()
00193 {
00194 init_side_context_proxy(context);
00195 manager::add_gamestate_observer(this);
00196
00197 add_known_aspect("aggression",aggression_);
00198 add_known_aspect("attack_depth",attack_depth_);
00199 add_known_aspect("attacks",attacks_);
00200 add_known_aspect("avoid",avoid_);
00201 add_known_aspect("caution",caution_);
00202 add_known_aspect("grouping",grouping_);
00203 add_known_aspect("leader_aggression",leader_aggression_);
00204 add_known_aspect("leader_goal",leader_goal_);
00205 add_known_aspect("leader_value",leader_value_);
00206 add_known_aspect("number_of_possible_recruits_to_force_recruit",number_of_possible_recruits_to_force_recruit_);
00207 add_known_aspect("passive_leader",passive_leader_);
00208 add_known_aspect("passive_leader_shares_keep",passive_leader_shares_keep_);
00209 add_known_aspect("recruitment",recruitment_);
00210 add_known_aspect("recruitment_ignore_bad_combat",recruitment_ignore_bad_combat_);
00211 add_known_aspect("recruitment_ignore_bad_movement",recruitment_ignore_bad_movement_);
00212 add_known_aspect("recruitment_pattern",recruitment_pattern_);
00213 add_known_aspect("scout_village_targeting",scout_village_targeting_);
00214 add_known_aspect("simple_targeting",simple_targeting_);
00215 add_known_aspect("support_villages",support_villages_);
00216 add_known_aspect("village_value",village_value_);
00217 add_known_aspect("villages_per_scout",villages_per_scout_);
00218 keeps_.init(*resources::game_map);
00219
00220 }
00221
00222 void readonly_context_impl::on_readonly_context_create() {
00223
00224 foreach(const config &cfg_element, cfg_.child_range("engine")){
00225 engine::parse_engine_from_config(*this,cfg_element,std::back_inserter(engines_));
00226 }
00227
00228
00229 foreach(const config &cfg_element, cfg_.child_range("aspect")){
00230 std::vector<aspect_ptr> aspects;
00231 engine::parse_aspect_from_config(*this,cfg_element,cfg_element["id"],std::back_inserter(aspects));
00232 add_aspects(aspects);
00233 }
00234
00235
00236 foreach(const config &cfg_element, cfg_.child_range("goal")){
00237 engine::parse_goal_from_config(*this,cfg_element,std::back_inserter(get_goals()));
00238 }
00239 }
00240
00241
00242 config side_context_impl::to_side_context_config() const
00243 {
00244 return config();
00245 }
00246
00247 config readwrite_context_impl::to_readwrite_context_config() const
00248 {
00249 return config();
00250 }
00251
00252
00253 config readonly_context_impl::to_readonly_context_config() const
00254 {
00255 config cfg;
00256 foreach(const engine_ptr e, engines_) {
00257 cfg.add_child("engine",e->to_config());
00258 }
00259 foreach(const aspect_map::value_type a, aspects_) {
00260 cfg.add_child("aspect",a.second->to_config());
00261 }
00262 foreach(const goal_ptr g, goals_) {
00263 cfg.add_child("goal",g->to_config());
00264 }
00265 return cfg;
00266 }
00267
00268 readonly_context_impl::~readonly_context_impl()
00269 {
00270 manager::remove_gamestate_observer(this);
00271 }
00272
00273 void readonly_context_impl::handle_generic_event(const std::string& )
00274 {
00275 invalidate_move_maps();
00276 }
00277
00278
00279 const game_info& readonly_context_impl::get_info() const{
00280 return manager::get_active_ai_info_for_side(get_side());
00281 }
00282
00283
00284 game_info& readwrite_context_impl::get_info_w(){
00285 return manager::get_active_ai_info_for_side(get_side());
00286 }
00287
00288 void readonly_context_impl::diagnostic(const std::string& msg)
00289 {
00290 if(game_config::debug) {
00291 resources::screen->set_diagnostic(msg);
00292 }
00293 }
00294
00295
00296 const team& readonly_context_impl::current_team() const
00297 {
00298 return (*resources::teams)[get_side()-1];
00299 }
00300
00301
00302 void readonly_context_impl::log_message(const std::string& msg)
00303 {
00304 if(game_config::debug) {
00305 resources::screen->add_chat_message(time(NULL), "ai", get_side(), msg,
00306 events::chat_handler::MESSAGE_PUBLIC, false);
00307 }
00308 }
00309
00310
00311 void readonly_context_impl::calculate_possible_moves(std::map<map_location,pathfind::paths>& res, move_map& srcdst,
00312 move_map& dstsrc, bool enemy, bool assume_full_movement,
00313 const terrain_filter* remove_destinations) const
00314 {
00315 calculate_moves(*resources::units,res,srcdst,dstsrc,enemy,assume_full_movement,remove_destinations);
00316 }
00317
00318 void readonly_context_impl::calculate_moves(const unit_map& units, std::map<map_location,pathfind::paths>& res, move_map& srcdst,
00319 move_map& dstsrc, bool enemy, bool assume_full_movement,
00320 const terrain_filter* remove_destinations,
00321 bool see_all
00322 ) const
00323 {
00324
00325 for(unit_map::const_iterator un_it = units.begin(); un_it != units.end(); ++un_it) {
00326
00327
00328
00329 if ((enemy && current_team().is_enemy(un_it->side()) == false) ||
00330 (!enemy && !assume_full_movement && un_it->side() != get_side()) ||
00331 (!enemy && assume_full_movement && current_team().is_enemy(un_it->side()))) {
00332 continue;
00333 }
00334
00335 if (un_it->incapacitated() ||
00336 (!assume_full_movement && un_it->movement_left() == 0)) {
00337 continue;
00338 }
00339
00340
00341 if (enemy && un_it->invisible(un_it->get_location()) && !see_all) {
00342 continue;
00343 }
00344
00345 unit* held_unit = const_cast<unit *>(&*un_it);
00346 const unit_movement_resetter move_resetter(*held_unit,enemy || assume_full_movement);
00347
00348
00349 if (un_it->movement_left() > 0) {
00350 std::pair<map_location,map_location> trivial_mv(un_it->get_location(), un_it->get_location());
00351 srcdst.insert(trivial_mv);
00352 dstsrc.insert(trivial_mv);
00353 }
00354 res.insert(std::pair<map_location,pathfind::paths>(
00355 un_it->get_location(), pathfind::paths(*resources::game_map,
00356 units, *un_it, *resources::teams, false,
00357 true, current_team(), 0, see_all)));
00358 }
00359
00360
00361 static const config only_not_tag("not");
00362 if(remove_destinations && remove_destinations->to_config() == only_not_tag) {
00363 remove_destinations = NULL;
00364 }
00365
00366 for(std::map<map_location,pathfind::paths>::iterator m = res.begin(); m != res.end(); ++m) {
00367 foreach (const pathfind::paths::step &dest, m->second.destinations)
00368 {
00369 const map_location& src = m->first;
00370 const map_location& dst = dest.curr;
00371
00372 if(remove_destinations != NULL && remove_destinations->match(dst)) {
00373 continue;
00374 }
00375
00376 bool friend_owns = false;
00377
00378
00379 if(!enemy && resources::game_map->is_village(dst)) {
00380 for(size_t n = 0; n != resources::teams->size(); ++n) {
00381 if((*resources::teams)[n].owns_village(dst)) {
00382 int side = n + 1;
00383 if (get_side() != side && !current_team().is_enemy(side)) {
00384 friend_owns = true;
00385 }
00386
00387 break;
00388 }
00389 }
00390 }
00391
00392 if(friend_owns) {
00393 continue;
00394 }
00395
00396 if(src != dst && (find_visible_unit(dst, current_team()) == resources::units->end()) ) {
00397 srcdst.insert(std::pair<map_location,map_location>(src,dst));
00398 dstsrc.insert(std::pair<map_location,map_location>(dst,src));
00399 }
00400 }
00401 }
00402 }
00403
00404
00405 void readonly_context_impl::add_aspects(std::vector< aspect_ptr > &aspects )
00406 {
00407 foreach (aspect_ptr a, aspects) {
00408 const std::string id = a->get_id();
00409 known_aspect_map::iterator i = known_aspects_.find(id);
00410 if (i != known_aspects_.end()) {
00411 i->second->set(a);
00412 } else {
00413 ERR_AI << "when adding aspects, unknown aspect id["<<id<<"]"<<std::endl;
00414 }
00415 }
00416 }
00417
00418 void readonly_context_impl::add_facet(const std::string &id, const config &cfg) const
00419 {
00420 known_aspect_map::const_iterator i = known_aspects_.find(id);
00421 if (i != known_aspects_.end()) {
00422 i->second->add_facet(cfg);
00423 } else {
00424 ERR_AI << "when adding aspects, unknown aspect id["<<id<<"]"<<std::endl;
00425 }
00426 }
00427
00428 const defensive_position& readonly_context_impl::best_defensive_position(const map_location& loc,
00429 const move_map& dstsrc, const move_map& srcdst, const move_map& enemy_dstsrc) const
00430 {
00431 const unit_map::const_iterator itor = resources::units->find(loc);
00432 if(itor == resources::units->end()) {
00433 static defensive_position pos;
00434 pos.chance_to_hit = 0;
00435 pos.vulnerability = pos.support = 0;
00436 return pos;
00437 }
00438
00439 const std::map<map_location,defensive_position>::const_iterator position =
00440 defensive_position_cache_.find(loc);
00441
00442 if(position != defensive_position_cache_.end()) {
00443 return position->second;
00444 }
00445
00446 defensive_position pos;
00447 pos.chance_to_hit = 100;
00448 pos.vulnerability = 10000.0;
00449 pos.support = 0.0;
00450
00451 typedef move_map::const_iterator Itor;
00452 const std::pair<Itor,Itor> itors = srcdst.equal_range(loc);
00453 for(Itor i = itors.first; i != itors.second; ++i) {
00454 const int defense = itor->defense_modifier(resources::game_map->get_terrain(i->second));
00455 if(defense > pos.chance_to_hit) {
00456 continue;
00457 }
00458
00459 const double vulnerability = power_projection(i->second,enemy_dstsrc);
00460 const double support = power_projection(i->second,dstsrc);
00461
00462 if(defense < pos.chance_to_hit || support - vulnerability > pos.support - pos.vulnerability) {
00463 pos.loc = i->second;
00464 pos.chance_to_hit = defense;
00465 pos.vulnerability = vulnerability;
00466 pos.support = support;
00467 }
00468 }
00469
00470 defensive_position_cache_.insert(std::pair<map_location,defensive_position>(loc,pos));
00471 return defensive_position_cache_[loc];
00472 }
00473
00474
00475 std::map<map_location,defensive_position>& readonly_context_impl::defensive_position_cache() const
00476 {
00477 return defensive_position_cache_;
00478 }
00479
00480
00481 double readonly_context_impl::get_aggression() const
00482 {
00483 if (aggression_) {
00484 return aggression_->get();
00485 }
00486 return 0;
00487 }
00488
00489
00490 int readonly_context_impl::get_attack_depth() const
00491 {
00492 if (attack_depth_) {
00493 return std::max<int>(1,attack_depth_->get());
00494 }
00495 return 1;
00496 }
00497
00498
00499 const aspect_map& readonly_context_impl::get_aspects() const
00500 {
00501 return aspects_;
00502 }
00503
00504
00505 aspect_map& readonly_context_impl::get_aspects()
00506 {
00507 return aspects_;
00508 }
00509
00510
00511 const attacks_vector& readonly_context_impl::get_attacks() const
00512 {
00513 if (attacks_) {
00514 return attacks_->get();
00515 }
00516 static attacks_vector av;
00517 return av;
00518 }
00519
00520
00521 const variant& readonly_context_impl::get_attacks_as_variant() const
00522 {
00523 if (attacks_) {
00524 return attacks_->get_variant();
00525 }
00526 static variant v;
00527 return v;
00528 }
00529
00530 const terrain_filter& readonly_context_impl::get_avoid() const
00531 {
00532 if (avoid_) {
00533 return avoid_->get();
00534 }
00535 config cfg;
00536 cfg.add_child("not");
00537 static terrain_filter tf(vconfig(cfg),*resources::units);
00538 return tf;
00539 }
00540
00541
00542 double readonly_context_impl::get_caution() const
00543 {
00544 if (caution_) {
00545 return caution_->get();
00546 }
00547 return 0;
00548 }
00549
00550 const move_map& readonly_context_impl::get_dstsrc() const
00551 {
00552 if (!move_maps_valid_) {
00553 recalculate_move_maps();
00554 }
00555 return dstsrc_;
00556 }
00557
00558
00559 const move_map& readonly_context_impl::get_enemy_dstsrc() const
00560 {
00561 if (!move_maps_enemy_valid_) {
00562 recalculate_move_maps_enemy();
00563 }
00564 return enemy_dstsrc_;
00565 }
00566
00567
00568 const moves_map& readonly_context_impl::get_enemy_possible_moves() const
00569 {
00570 if (!move_maps_enemy_valid_) {
00571 recalculate_move_maps_enemy();
00572 }
00573 return enemy_possible_moves_;
00574 }
00575
00576
00577 const move_map& readonly_context_impl::get_enemy_srcdst() const
00578 {
00579 if (!move_maps_enemy_valid_) {
00580 recalculate_move_maps_enemy();
00581 }
00582 return enemy_srcdst_;
00583 }
00584
00585
00586 engine_ptr readonly_context_impl::get_engine_by_cfg(const config& cfg)
00587 {
00588 std::string engine_name = cfg["engine"];
00589 if (engine_name.empty()) {
00590 engine_name="cpp";
00591 }
00592
00593 std::vector<engine_ptr>::iterator en = engines_.begin();
00594 while (en!=engines_.end() && ((*en)->get_name()!=engine_name) && ((*en)->get_id()!=engine_name)) {
00595 ++en;
00596 }
00597
00598 if (en != engines_.end()){
00599 return *en;
00600 }
00601
00602
00603 engine_factory::factory_map::iterator eng = engine_factory::get_list().find(engine_name);
00604 if (eng == engine_factory::get_list().end()){
00605 ERR_AI << "side "<<get_side()<<" : UNABLE TO FIND engine["<<
00606 engine_name <<"]" << std::endl;
00607 DBG_AI << "config snippet contains: " << std::endl << cfg << std::endl;
00608 return engine_ptr();
00609 }
00610
00611 engine_ptr new_engine = eng->second->get_new_instance(*this,engine_name);
00612 if (!new_engine) {
00613 ERR_AI << "side "<<get_side()<<" : UNABLE TO CREATE engine["<<
00614 engine_name <<"] " << std::endl;
00615 DBG_AI << "config snippet contains: " << std::endl << cfg << std::endl;
00616 return engine_ptr();
00617 }
00618 engines_.push_back(new_engine);
00619 return engines_.back();
00620 }
00621
00622
00623 const std::vector<engine_ptr>& readonly_context_impl::get_engines() const
00624 {
00625 return engines_;
00626 }
00627
00628
00629 std::vector<engine_ptr>& readonly_context_impl::get_engines()
00630 {
00631 return engines_;
00632 }
00633
00634
00635 std::string readonly_context_impl::get_grouping() const
00636 {
00637 if (grouping_) {
00638 return grouping_->get();
00639 }
00640 return std::string();
00641 }
00642
00643
00644 const std::vector<goal_ptr>& readonly_context_impl::get_goals() const
00645 {
00646 return goals_;
00647 }
00648
00649
00650 std::vector<goal_ptr>& readonly_context_impl::get_goals()
00651 {
00652 return goals_;
00653 }
00654
00655
00656
00657 double readonly_context_impl::get_leader_aggression() const
00658 {
00659 if (leader_aggression_) {
00660 return leader_aggression_->get();
00661 }
00662 return 0;
00663 }
00664
00665
00666 config readonly_context_impl::get_leader_goal() const
00667 {
00668 if (leader_goal_) {
00669 return leader_goal_->get();
00670 }
00671 return config();
00672 }
00673
00674
00675 double readonly_context_impl::get_leader_value() const
00676 {
00677 if (leader_value_) {
00678 return leader_value_->get();
00679 }
00680 return 0;
00681 }
00682
00683
00684 double readonly_context_impl::get_number_of_possible_recruits_to_force_recruit() const
00685 {
00686 if (number_of_possible_recruits_to_force_recruit_) {
00687 return number_of_possible_recruits_to_force_recruit_->get();
00688 }
00689 return 0;
00690 }
00691
00692
00693 bool readonly_context_impl::get_passive_leader() const
00694 {
00695 if (passive_leader_) {
00696 return passive_leader_->get();
00697 }
00698 return false;
00699 }
00700
00701
00702 bool readonly_context_impl::get_passive_leader_shares_keep() const
00703 {
00704 if (passive_leader_shares_keep_) {
00705 return passive_leader_shares_keep_->get();
00706 }
00707 return false;
00708 }
00709
00710
00711 const moves_map& readonly_context_impl::get_possible_moves() const
00712 {
00713 if (!move_maps_valid_) {
00714 recalculate_move_maps();
00715 }
00716 return possible_moves_;
00717 }
00718
00719
00720 const std::vector<unit>& readonly_context_impl::get_recall_list() const
00721 {
00722 static std::vector<unit> dummy_units;
00723
00724 if(!current_team().persistent()) {
00725 return dummy_units;
00726 }
00727
00728 return current_team().recall_list();
00729 }
00730
00731 stage_ptr readonly_context_impl::get_recruitment(ai_context &context) const
00732 {
00733 if (recruitment_) {
00734 ministage_ptr m = recruitment_->get_ptr();
00735 if (m) {
00736 return m->get_stage_ptr(context);
00737 }
00738 }
00739 return stage_ptr();
00740 }
00741
00742
00743 bool readonly_context_impl::get_recruitment_ignore_bad_combat() const
00744 {
00745 if (recruitment_ignore_bad_combat_) {
00746 return recruitment_ignore_bad_combat_->get();
00747 }
00748 return false;
00749 }
00750
00751
00752 bool readonly_context_impl::get_recruitment_ignore_bad_movement() const
00753 {
00754 if (recruitment_ignore_bad_movement_) {
00755 return recruitment_ignore_bad_movement_->get();
00756 }
00757 return false;
00758 }
00759
00760
00761 const std::vector<std::string> readonly_context_impl::get_recruitment_pattern() const
00762 {
00763 if (recruitment_pattern_) {
00764 return recruitment_pattern_->get();
00765 }
00766 return std::vector<std::string>();
00767 }
00768
00769
00770 double readonly_context_impl::get_scout_village_targeting() const
00771 {
00772 if (scout_village_targeting_) {
00773 return scout_village_targeting_->get();
00774 }
00775 return 1;
00776 }
00777
00778
00779 bool readonly_context_impl::get_simple_targeting() const
00780 {
00781 if (simple_targeting_) {
00782 return simple_targeting_->get();
00783 }
00784 return false;
00785 }
00786
00787
00788 const move_map& readonly_context_impl::get_srcdst() const
00789 {
00790 if (!move_maps_valid_) {
00791 recalculate_move_maps();
00792 }
00793 return srcdst_;
00794 }
00795
00796
00797 bool readonly_context_impl::get_support_villages() const
00798 {
00799 if (support_villages_) {
00800 return support_villages_->get();
00801 }
00802 return false;
00803 }
00804
00805
00806 double readonly_context_impl::get_village_value() const
00807 {
00808 if (village_value_) {
00809 return village_value_->get();
00810 }
00811 return 0;
00812 }
00813
00814
00815 int readonly_context_impl::get_villages_per_scout() const
00816 {
00817 if (villages_per_scout_) {
00818 return villages_per_scout_->get();
00819 }
00820 return 0;
00821 }
00822
00823 bool readonly_context_impl::is_dst_src_valid_lua() const
00824 {
00825 return dst_src_valid_lua_;
00826 }
00827
00828 bool readonly_context_impl::is_dst_src_enemy_valid_lua() const
00829 {
00830 return dst_src_enemy_valid_lua_;
00831 }
00832
00833 bool readonly_context_impl::is_src_dst_valid_lua() const
00834 {
00835 return src_dst_valid_lua_;
00836 }
00837
00838 bool readonly_context_impl::is_src_dst_enemy_valid_lua() const
00839 {
00840 return src_dst_enemy_valid_lua_;
00841 }
00842
00843 void readonly_context_impl::invalidate_defensive_position_cache() const
00844 {
00845 defensive_position_cache_.clear();
00846 }
00847
00848
00849 void readonly_context_impl::invalidate_keeps_cache() const
00850 {
00851 keeps_.clear();
00852 }
00853
00854
00855 void keeps_cache::handle_generic_event(const std::string &)
00856 {
00857 clear();
00858 }
00859
00860
00861 void readonly_context_impl::invalidate_move_maps() const
00862 {
00863 move_maps_valid_ = false;
00864 move_maps_enemy_valid_ = false;
00865
00866 dst_src_valid_lua_ = false;
00867 dst_src_enemy_valid_lua_ = false;
00868
00869 src_dst_valid_lua_ = false;
00870 src_dst_enemy_valid_lua_ = false;
00871 }
00872
00873
00874 const std::set<map_location>& readonly_context_impl::keeps() const
00875 {
00876 return keeps_.get();
00877 }
00878
00879
00880 keeps_cache::keeps_cache()
00881 : map_(NULL)
00882 , keeps_()
00883 {
00884 ai::manager::add_turn_started_observer(this);
00885 ai::manager::add_map_changed_observer(this);
00886 }
00887
00888
00889 keeps_cache::~keeps_cache()
00890 {
00891 ai::manager::remove_turn_started_observer(this);
00892 ai::manager::remove_map_changed_observer(this);
00893 }
00894
00895 void keeps_cache::clear()
00896 {
00897 keeps_.clear();
00898 }
00899
00900
00901 void keeps_cache::init(gamemap &map)
00902 {
00903 map_ = ↦
00904 }
00905
00906 const std::set<map_location>& keeps_cache::get()
00907 {
00908 if(keeps_.empty()) {
00909
00910
00911 for(size_t x = 0; x != size_t(map_->w()); ++x) {
00912 for(size_t y = 0; y != size_t(map_->h()); ++y) {
00913 const map_location loc(x,y);
00914 if(map_->is_keep(loc)) {
00915 map_location adj[6];
00916 get_adjacent_tiles(loc,adj);
00917 for(size_t n = 0; n != 6; ++n) {
00918 if(map_->is_castle(adj[n])) {
00919 keeps_.insert(loc);
00920 break;
00921 }
00922 }
00923 }
00924 }
00925 }
00926 }
00927
00928 return keeps_;
00929 }
00930
00931
00932 bool readonly_context_impl::leader_can_reach_keep() const
00933 {
00934 const unit_map::iterator leader = resources::units->find_leader(get_side());
00935 if(leader == resources::units->end() || leader->incapacitated()) {
00936 return false;
00937 }
00938
00939 const map_location &start_pos = nearest_keep(leader->get_location());
00940 if(start_pos.valid() == false) {
00941 return false;
00942 }
00943
00944 if (leader->get_location() == start_pos) {
00945 return true;
00946 }
00947
00948
00949 const pathfind::paths leader_paths(*resources::game_map, *resources::units,
00950 *leader, *resources::teams, false, true, current_team());
00951
00952 return leader_paths.destinations.contains(start_pos);
00953 }
00954
00955
00956 const map_location& readonly_context_impl::nearest_keep(const map_location& loc) const
00957 {
00958 std::set<map_location> avoided_locations;
00959 get_avoid().get_locations(avoided_locations);
00960 const std::set<map_location>& keeps = this->keeps();
00961 if(keeps.empty()) {
00962 static const map_location dummy;
00963 return dummy;
00964 }
00965
00966 const map_location* res = NULL;
00967 int closest = -1;
00968 for(std::set<map_location>::const_iterator i = keeps.begin(); i != keeps.end(); ++i) {
00969 if (avoided_locations.find(*i)!=avoided_locations.end()) {
00970 continue;
00971 }
00972 const int distance = distance_between(*i,loc);
00973 if(res == NULL || distance < closest) {
00974 closest = distance;
00975 res = &*i;
00976 }
00977 }
00978 if (res) {
00979 return *res;
00980 } else {
00981 return map_location::null_location;
00982 }
00983 }
00984
00985
00986 double readonly_context_impl::power_projection(const map_location& loc, const move_map& dstsrc) const
00987 {
00988 map_location used_locs[6];
00989 int ratings[6];
00990 int num_used_locs = 0;
00991
00992 map_location locs[6];
00993 get_adjacent_tiles(loc,locs);
00994
00995 gamemap& map_ = *resources::game_map;
00996 unit_map& units_ = *resources::units;
00997
00998 int res = 0;
00999
01000 bool changed = false;
01001 for (int i = 0;; ++i) {
01002 if (i == 6) {
01003 if (!changed) break;
01004
01005
01006 changed = false;
01007 i = 0;
01008 }
01009
01010 if (map_.on_board(locs[i]) == false) {
01011 continue;
01012 }
01013
01014 const t_translation::t_terrain terrain = map_[locs[i]];
01015
01016 typedef move_map::const_iterator Itor;
01017 typedef std::pair<Itor,Itor> Range;
01018 Range its = dstsrc.equal_range(locs[i]);
01019
01020 map_location* const beg_used = used_locs;
01021 map_location* end_used = used_locs + num_used_locs;
01022
01023 int best_rating = 0;
01024 map_location best_unit;
01025
01026 for(Itor it = its.first; it != its.second; ++it) {
01027 const unit_map::const_iterator u = units_.find(it->second);
01028
01029
01030 if(u == units_.end()) {
01031 continue;
01032 }
01033
01034 const unit& un = *u;
01035
01036
01037 int attack_turn = resources::tod_manager->turn();
01038 if(un.side() < get_side()) {
01039 ++attack_turn;
01040 }
01041
01042 const int lawful_bonus = resources::tod_manager->get_time_of_day(attack_turn).lawful_bonus;
01043 int tod_modifier = 0;
01044 if(un.alignment() == unit_type::LAWFUL) {
01045 tod_modifier = lawful_bonus;
01046 } else if(un.alignment() == unit_type::CHAOTIC) {
01047 tod_modifier = -lawful_bonus;
01048 } else if(un.alignment() == unit_type::LIMINAL) {
01049 tod_modifier = -(abs(lawful_bonus));
01050 }
01051
01052
01053 int hp = int(sqrt(double(un.hitpoints()) / un.max_hitpoints()) * 1000);
01054 int most_damage = 0;
01055 foreach (const attack_type &att, un.attacks())
01056 {
01057 int damage = att.damage() * att.num_attacks() * (100 + tod_modifier);
01058 if (damage > most_damage) {
01059 most_damage = damage;
01060 }
01061 }
01062
01063 int village_bonus = map_.is_village(terrain) ? 3 : 2;
01064 int defense = 100 - un.defense_modifier(terrain);
01065 int rating = hp * defense * most_damage * village_bonus / 200;
01066 if(rating > best_rating) {
01067 map_location *pos = std::find(beg_used, end_used, it->second);
01068
01069 if (pos == end_used || rating >= ratings[pos - beg_used]) {
01070 best_rating = rating;
01071 best_unit = it->second;
01072 }
01073 }
01074 }
01075
01076 if (!best_unit.valid()) continue;
01077 map_location *pos = std::find(beg_used, end_used, best_unit);
01078 int index = pos - beg_used;
01079 if (index == num_used_locs)
01080 ++num_used_locs;
01081 else if (best_rating == ratings[index])
01082 continue;
01083 else {
01084
01085
01086 res -= ratings[index];
01087 changed = true;
01088 }
01089 used_locs[index] = best_unit;
01090 ratings[index] = best_rating;
01091 res += best_rating;
01092 }
01093
01094 return res / 100000.;
01095 }
01096
01097 void readonly_context_impl::recalculate_move_maps() const
01098 {
01099 dstsrc_ = move_map();
01100 possible_moves_ = moves_map();
01101 srcdst_ = move_map();
01102 calculate_possible_moves(possible_moves_,srcdst_,dstsrc_,false,false,&get_avoid());
01103 if (get_passive_leader()||get_passive_leader_shares_keep()) {
01104 unit_map::iterator i = resources::units->find_leader(get_side());
01105 if (i.valid()) {
01106 map_location loc = i->get_location();
01107 srcdst_.erase(loc);
01108 for(move_map::iterator i = dstsrc_.begin(); i != dstsrc_.end(); ) {
01109 if(i->second == loc) {
01110 dstsrc_.erase(i++);
01111 } else {
01112 ++i;
01113 }
01114 }
01115
01116 }
01117 }
01118 move_maps_valid_ = true;
01119
01120
01121 dst_src_valid_lua_ = false;
01122 src_dst_valid_lua_ = false;
01123 }
01124
01125
01126 void readonly_context_impl::recalculate_move_maps_enemy() const
01127 {
01128 enemy_dstsrc_ = move_map();
01129 enemy_srcdst_ = move_map();
01130 enemy_possible_moves_ = moves_map();
01131 calculate_possible_moves(enemy_possible_moves_,enemy_srcdst_,enemy_dstsrc_,true);
01132 move_maps_enemy_valid_ = true;
01133
01134
01135 dst_src_enemy_valid_lua_ = false;
01136 src_dst_enemy_valid_lua_ = false;
01137 }
01138
01139 void readonly_context_impl::set_dst_src_valid_lua()
01140 {
01141 dst_src_valid_lua_ = true;
01142 }
01143
01144 void readonly_context_impl::set_dst_src_enemy_valid_lua()
01145 {
01146 dst_src_enemy_valid_lua_ = true;
01147 }
01148
01149 void readonly_context_impl::set_src_dst_valid_lua()
01150 {
01151 src_dst_valid_lua_ = true;
01152 }
01153
01154 void readonly_context_impl::set_src_dst_enemy_valid_lua()
01155 {
01156 src_dst_enemy_valid_lua_ = true;
01157 }
01158
01159 const map_location& readonly_context_impl::suitable_keep(const map_location& leader_location, const pathfind::paths& leader_paths){
01160 if (resources::game_map->is_keep(leader_location)) {
01161 return leader_location;
01162 }
01163
01164 map_location const* best_free_keep = &map_location::null_location;
01165 double move_left_at_best_free_keep = 0.0;
01166
01167 map_location const* best_occupied_keep = &map_location::null_location;
01168 double move_left_at_best_occupied_keep = 0.0;
01169
01170 foreach (const pathfind::paths::step &dest, leader_paths.destinations)
01171 {
01172 const map_location &loc = dest.curr;
01173 if (keeps().find(loc)!=keeps().end()){
01174
01175 const int move_left_at_loc = dest.move_left;
01176 if (resources::units->count(loc) == 0) {
01177 if ((*best_free_keep==map_location::null_location)||(move_left_at_loc>move_left_at_best_free_keep)){
01178 best_free_keep = &loc;
01179 move_left_at_best_free_keep = move_left_at_loc;
01180 }
01181 } else {
01182 if ((*best_occupied_keep==map_location::null_location)||(move_left_at_loc>move_left_at_best_occupied_keep)){
01183 best_occupied_keep = &loc;
01184 move_left_at_best_occupied_keep = move_left_at_loc;
01185 }
01186 }
01187 }
01188 }
01189
01190 if (*best_free_keep != map_location::null_location){
01191 return *best_free_keep;
01192 }
01193
01194 if (*best_occupied_keep != map_location::null_location){
01195 return *best_occupied_keep;
01196 }
01197
01198 return nearest_keep(leader_location);
01199 }
01200
01201
01202
01203 std::map<std::pair<map_location,const unit_type *>,
01204 std::pair<battle_context_unit_stats,battle_context_unit_stats> >& readonly_context_impl::unit_stats_cache() const
01205 {
01206 return unit_stats_cache_;
01207 }
01208
01209
01210 bool readonly_context_impl::is_active(const std::string &time_of_day, const std::string &turns) const
01211 {
01212 if(time_of_day.empty() == false) {
01213 const std::vector<std::string>& times = utils::split(time_of_day);
01214 if(std::count(times.begin(),times.end(),resources::tod_manager->get_time_of_day().name) == 0) {
01215 return false;
01216 }
01217 }
01218
01219 if(turns.empty() == false) {
01220 int turn = resources::tod_manager->turn();
01221 const std::vector<std::string>& turns_list = utils::split(turns);
01222 for(std::vector<std::string>::const_iterator j = turns_list.begin(); j != turns_list.end() ; ++j ) {
01223 const std::pair<int,int> range = utils::parse_range(*j);
01224 if(turn >= range.first && turn <= range.second) {
01225 return true;
01226 }
01227 }
01228 return false;
01229 }
01230 return true;
01231 }
01232
01233 }