doxygen, comments
This commit is contained in:
parent
29123929b8
commit
0679c0cbab
2 changed files with 218 additions and 185 deletions
286
src/ai.cpp
286
src/ai.cpp
|
@ -13,6 +13,10 @@
|
|||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
|
||||
//! @file ai.cpp
|
||||
//! Artificial intelligence - The computer commands the enemy.
|
||||
|
||||
#include "ai.hpp"
|
||||
#include "ai2.hpp"
|
||||
#include "ai_dfool.hpp"
|
||||
|
@ -35,7 +39,7 @@
|
|||
#define WRN_AI LOG_STREAM(warn, ai)
|
||||
#define ERR_AI LOG_STREAM(err, ai)
|
||||
|
||||
///a trivial ai that sits around doing absolutely nothing
|
||||
//! A trivial ai that sits around doing absolutely nothing.
|
||||
class idle_ai : public ai_interface {
|
||||
public:
|
||||
idle_ai(info& i) : ai_interface(i) {}
|
||||
|
@ -44,6 +48,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
//! Sample ai, with simple strategy.
|
||||
class sample_ai : public ai_interface {
|
||||
public:
|
||||
sample_ai(info& i) : ai_interface(i) {}
|
||||
|
@ -184,10 +189,10 @@ std::vector<std::string> get_available_ais()
|
|||
|
||||
ai_interface* create_ai(const std::string& name, ai_interface::info& info)
|
||||
{
|
||||
//to add an AI of your own, put
|
||||
//if(name == "my_ai")
|
||||
// return new my_ai(info);
|
||||
//at the top of this function
|
||||
// To add an AI of your own, put
|
||||
// if(name == "my_ai")
|
||||
// return new my_ai(info);
|
||||
// at the top of this function
|
||||
|
||||
if(name == "sample_ai")
|
||||
return new sample_ai(info);
|
||||
|
@ -232,8 +237,8 @@ bool ai::recruit_usage(const std::string& usage)
|
|||
|
||||
std::vector<std::string> options;
|
||||
|
||||
//find an available unit that can be recruited, matches the desired
|
||||
//usage type, and comes in under budget
|
||||
// Find an available unit that can be recruited,
|
||||
// matches the desired usage type, and comes in under budget.
|
||||
const std::set<std::string>& recruits = current_team().recruits();
|
||||
for(std::map<std::string,unit_type>::const_iterator i =
|
||||
gameinfo_.unit_types.begin(); i != gameinfo_.unit_types.end(); ++i) {
|
||||
|
@ -248,7 +253,7 @@ bool ai::recruit_usage(const std::string& usage)
|
|||
}
|
||||
}
|
||||
|
||||
//from the available options, choose one at random
|
||||
// From the available options, choose one at random
|
||||
if(options.empty() == false) {
|
||||
const int option = rand()%options.size();
|
||||
return recruit(options[option]);
|
||||
|
@ -270,11 +275,12 @@ bool ai_interface::recruit(const std::string& unit_name, location loc)
|
|||
|
||||
const int num = std::distance(recruits.begin(),i);
|
||||
|
||||
//we have to add the recruit command now, because when the unit is created it has
|
||||
//to have the recruit command in the recorder to be able to put random numbers into
|
||||
//to generate unit traits. However we're not sure the transaction is going through yet,
|
||||
//so use a replay_undo object to cancel it if we don't get to the point where the transaction
|
||||
//is confirmed
|
||||
// We have to add the recruit command now, because when the unit
|
||||
// is created it has to have the recruit command in the recorder
|
||||
// to be able to put random numbers into to generate unit traits.
|
||||
// However, we're not sure if the transaction will be successful,
|
||||
// so use a replay_undo object to cancel it if we don't get
|
||||
// a confirmation for the transaction.
|
||||
recorder.add_recruit(num,loc);
|
||||
replay_undo replay_guard(recorder);
|
||||
|
||||
|
@ -283,7 +289,7 @@ bool ai_interface::recruit(const std::string& unit_name, location loc)
|
|||
return false;
|
||||
}
|
||||
|
||||
//check we have enough money
|
||||
// Check if we have enough money
|
||||
if(current_team().gold() < u->second.cost()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -296,13 +302,13 @@ bool ai_interface::recruit(const std::string& unit_name, location loc)
|
|||
|
||||
unit new_unit(&info_.gameinfo,&info_.units,&info_.map,&info_.state,&info_.teams,&u->second,info_.team_num,true);
|
||||
|
||||
//see if we can actually recruit (i.e. have enough room etc)
|
||||
// See if we can actually recruit (i.e. have enough room etc.)
|
||||
if(recruit_unit(info_.map,info_.team_num,info_.units,new_unit,loc,preferences::show_ai_moves()).empty()) {
|
||||
|
||||
statistics::recruit_unit(new_unit);
|
||||
current_team().spend_gold(u->second.cost());
|
||||
|
||||
//confirm the transaction - i.e. don't undo recruitment
|
||||
// Confirm the transaction - i.e. don't undo recruitment
|
||||
replay_guard.confirm_transaction();
|
||||
|
||||
raise_unit_recruited();
|
||||
|
@ -377,7 +383,7 @@ gamemap::location ai_interface::move_unit_partial(location from, location to,
|
|||
{
|
||||
LOG_AI << "ai_interface::move_unit " << from << " -> " << to << '\n';
|
||||
|
||||
//stop the user from issuing any commands while the unit is moving
|
||||
// Stop the user from issuing any commands while the unit is moving.
|
||||
const events::command_disabler disable_commands;
|
||||
|
||||
//wassert(info_.units.find(to) == info_.units.end() || from == to);
|
||||
|
@ -429,14 +435,14 @@ gamemap::location ai_interface::move_unit_partial(location from, location to,
|
|||
LOG_AI << "\tresetting to " << from << " -> " << to << '\n';
|
||||
}
|
||||
|
||||
if(steps.size()>1) { //first step is starting hex
|
||||
if(steps.size()>1) { // First step is starting hex
|
||||
unit_map::const_iterator utest=info_.units.find(*(steps.begin()+1));
|
||||
if(utest != info_.units.end() && current_team().is_enemy(utest->second.side())){
|
||||
LOG_STREAM(err, ai) << "AI tried to move onto existing enemy unit at"<<*(steps.begin())<<"\n";
|
||||
// return(from);
|
||||
}
|
||||
|
||||
//check if there are any invisible units that we uncover
|
||||
// Check if there are any invisible units that we uncover
|
||||
for(std::vector<location>::iterator i = steps.begin()+1; i != steps.end(); ++i) {
|
||||
location adj[6];
|
||||
get_adjacent_tiles(*i,adj);
|
||||
|
@ -444,11 +450,11 @@ gamemap::location ai_interface::move_unit_partial(location from, location to,
|
|||
size_t n;
|
||||
for(n = 0; n != 6; ++n) {
|
||||
|
||||
//see if there is an enemy unit next to this tile. If it's invisible,
|
||||
//we need to stop: we're ambushed. If it's not, we must be a skirmisher,
|
||||
//otherwise AI wouldn't try.
|
||||
// See if there is an enemy unit next to this tile.
|
||||
// If it's invisible, we need to stop: we're ambushed.
|
||||
// If it's not, we must be a skirmisher, otherwise AI wouldn't try.
|
||||
|
||||
//or would it? If it doesn't cheat, it might...
|
||||
// Or would it? If it doesn't cheat, it might...
|
||||
const unit_map::const_iterator u = info_.units.find(adj[n]);
|
||||
if (u != info_.units.end() && u->second.emits_zoc()
|
||||
&& current_team().is_enemy(u->second.side())) {
|
||||
|
@ -476,13 +482,13 @@ gamemap::location ai_interface::move_unit_partial(location from, location to,
|
|||
}
|
||||
|
||||
if(n != 6) {
|
||||
u_it->second.set_movement(0); //enter enemy ZoC, no movement left
|
||||
u_it->second.set_movement(0); // Enter enemy ZoC, no movement left
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
steps.push_back(to); //add the destination to the steps
|
||||
steps.push_back(to); // Add the destination to the steps
|
||||
|
||||
if(show_move && unit_display::unit_visible_on_path(steps,
|
||||
u_it->second, info_.units,info_.teams)) {
|
||||
|
@ -501,7 +507,7 @@ gamemap::location ai_interface::move_unit_partial(location from, location to,
|
|||
info_.units.add(p);
|
||||
p->second.set_standing(info_.disp,p->first);
|
||||
if(info_.map.is_village(to)) {
|
||||
// if a new village is captured, disallow any future movement
|
||||
// If a new village is captured, disallow any future movement.
|
||||
if (!info_.teams[info_.team_num-1].owns_village(to))
|
||||
info_.units.find(to)->second.set_movement(-1);
|
||||
get_village(to,info_.teams,info_.team_num-1,info_.units);
|
||||
|
@ -543,8 +549,8 @@ bool ai::multistep_move_possible(location from, location to, location via,
|
|||
|
||||
int move_left = 0;
|
||||
|
||||
//see if the unit can make it to 'via', and if it can, how much movement it will have
|
||||
//left when it gets there.
|
||||
// See if the unit can make it to 'via', and if it can,
|
||||
// how much movement it will have left when it gets there.
|
||||
const paths::routes_map::const_iterator itor = moves->second.routes.find(via);
|
||||
if(itor != moves->second.routes.end()) {
|
||||
move_left = itor->second.move_left;
|
||||
|
@ -556,7 +562,7 @@ bool ai::multistep_move_possible(location from, location to, location via,
|
|||
|
||||
LOG_AI << "found " << unit_paths.routes.size() << " moves for temp leader\n";
|
||||
|
||||
//see if this leader could make it back to the keep
|
||||
// See if this leader could make it back to the keep.
|
||||
if(unit_paths.routes.count(to) != 0) {
|
||||
LOG_AI << "can make it back to the keep\n";
|
||||
return true;
|
||||
|
@ -577,11 +583,11 @@ gamemap::location ai::move_unit(location from, location to, std::map<location,pa
|
|||
const unit_map::const_iterator i = units_.find(from);
|
||||
if(i != units_.end() && i->second.can_recruit()) {
|
||||
|
||||
//if the leader isn't on its keep, and we can move to the keep and still make our planned
|
||||
//movement, then try doing that.
|
||||
// If the leader isn't on its keep, and we can move to the keep
|
||||
// and still make our planned movement, then try doing that.
|
||||
const gamemap::location& start_pos = nearest_keep(i->first);
|
||||
|
||||
//if we can make it back to the keep and then to our original destination, do so.
|
||||
// If we can make it back to the keep and then to our original destination, do so.
|
||||
if(multistep_move_possible(from,to,start_pos,possible_moves)) {
|
||||
from = ai_interface::move_unit(from,start_pos,possible_moves);
|
||||
if(from != start_pos) {
|
||||
|
@ -590,8 +596,8 @@ gamemap::location ai::move_unit(location from, location to, std::map<location,pa
|
|||
|
||||
const unit_map::iterator itor = units_.find(from);
|
||||
if(itor != units_.end()) {
|
||||
//just set the movement to one less than the maximum possible, since we know we
|
||||
//can reach the destination, and we're giong to move there immediately
|
||||
// Just set the movement to one less than the maximum possible, since we know
|
||||
// we can reach the destination, and we're going to move there immediately.
|
||||
itor->second.set_movement(itor->second.total_movement()-1);
|
||||
}
|
||||
|
||||
|
@ -606,7 +612,7 @@ gamemap::location ai::move_unit(location from, location to, std::map<location,pa
|
|||
if(units_.count(to) == 0 || from == to) {
|
||||
const location res = ai_interface::move_unit(from,to,*possible_moves_ptr);
|
||||
if(res != to) {
|
||||
//we've been ambushed; find the ambushing unit and attack them
|
||||
// We've been ambushed; find the ambushing unit and attack them.
|
||||
adjacent_tiles_array locs;
|
||||
get_adjacent_tiles(res,locs.data());
|
||||
for(adjacent_tiles_array::const_iterator adj_i = locs.begin(); adj_i != locs.end(); ++adj_i) {
|
||||
|
@ -660,28 +666,28 @@ void ai_interface::calculate_moves(const unit_map& units, std::map<location,path
|
|||
{
|
||||
|
||||
for(unit_map::const_iterator un_it = units.begin(); un_it != units.end(); ++un_it) {
|
||||
//if we are looking for the movement of enemies, then this unit must be an enemy unit
|
||||
//if we are looking for movement of our own units, it must be on our side.
|
||||
//if we are assuming full movement, then it may be a unit on our side, or allied
|
||||
// If we are looking for the movement of enemies, then this unit must be an enemy unit.
|
||||
// If we are looking for movement of our own units, it must be on our side.
|
||||
// If we are assuming full movement, then it may be a unit on our side, or allied.
|
||||
if(enemy && current_team().is_enemy(un_it->second.side()) == false ||
|
||||
!enemy && !assume_full_movement && un_it->second.side() != info_.team_num ||
|
||||
!enemy && assume_full_movement && current_team().is_enemy(un_it->second.side())) {
|
||||
continue;
|
||||
}
|
||||
//discount incapacitated units
|
||||
// Discount incapacitated units
|
||||
if(un_it->second.incapacitated()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//we can't see where invisible enemy units might move
|
||||
// We can't see where invisible enemy units might move.
|
||||
if(enemy && un_it->second.invisible(un_it->first,units,info_.teams) && !see_all) {
|
||||
continue;
|
||||
}
|
||||
//if it's an enemy unit, reset its moves while we do the calculations
|
||||
// If it's an enemy unit, reset its moves while we do the calculations.
|
||||
unit* held_unit = const_cast<unit*>(&(un_it->second));
|
||||
const unit_movement_resetter move_resetter(*held_unit,enemy || assume_full_movement);
|
||||
|
||||
//insert the trivial moves of staying on the same location
|
||||
// Insert the trivial moves of staying on the same location.
|
||||
if(un_it->second.movement_left() == un_it->second.total_movement()) {
|
||||
std::pair<location,location> trivial_mv(un_it->first,un_it->first);
|
||||
srcdst.insert(trivial_mv);
|
||||
|
@ -706,7 +712,7 @@ void ai_interface::calculate_moves(const unit_map& units, std::map<location,path
|
|||
|
||||
bool friend_owns = false;
|
||||
|
||||
//don't take friendly villages
|
||||
// Don't take friendly villages
|
||||
if(!enemy && info_.map.is_village(dst)) {
|
||||
for(size_t n = 0; n != info_.teams.size(); ++n) {
|
||||
if(info_.teams[n].owns_village(dst)) {
|
||||
|
@ -745,7 +751,7 @@ void ai::remove_unit_from_moves(const gamemap::location& loc, move_map& srcdst,
|
|||
|
||||
namespace {
|
||||
|
||||
//a structure to place an item we're trying to protect in
|
||||
//! A structure for storing an item we're trying to protect.
|
||||
struct protected_item {
|
||||
protected_item(double value, int radius, const gamemap::location& loc) :
|
||||
value(value), radius(radius), loc(loc) {}
|
||||
|
@ -770,7 +776,7 @@ void ai::find_threats()
|
|||
|
||||
std::vector<protected_item> items;
|
||||
|
||||
//we want to protect our leader
|
||||
// We want to protect our leader.
|
||||
const unit_map::const_iterator leader = find_leader(units_,team_num_);
|
||||
if(leader != units_.end()) {
|
||||
items.push_back(protected_item(
|
||||
|
@ -779,7 +785,7 @@ void ai::find_threats()
|
|||
leader->first));
|
||||
}
|
||||
|
||||
//look for directions to protect a specific location
|
||||
// Look for directions to protect a specific location.
|
||||
const config::child_list& locations = parms.get_children("protect_location");
|
||||
for(config::child_list::const_iterator i = locations.begin(); i != locations.end(); ++i) {
|
||||
items.push_back(protected_item(
|
||||
|
@ -788,7 +794,7 @@ void ai::find_threats()
|
|||
gamemap::location(**i, &get_info().game_state_)));
|
||||
}
|
||||
|
||||
//look for directions to protect a unit
|
||||
// Look for directions to protect a unit.
|
||||
const config::child_list& protected_units = parms.get_children("protect_unit");
|
||||
for(config::child_list::const_iterator j = protected_units.begin(); j != protected_units.end(); ++j) {
|
||||
|
||||
|
@ -802,8 +808,8 @@ void ai::find_threats()
|
|||
}
|
||||
}
|
||||
|
||||
//iterate over all protected locations, and if enemy units are within the protection radius, set them
|
||||
//as hostile targets
|
||||
// Iterate over all protected locations, and if enemy units
|
||||
// are within the protection radius, set them as hostile targets.
|
||||
for(std::vector<protected_item>::const_iterator k = items.begin(); k != items.end(); ++k) {
|
||||
const protected_item& item = *k;
|
||||
|
||||
|
@ -819,15 +825,16 @@ void ai::find_threats()
|
|||
|
||||
void ai::play_turn()
|
||||
{
|
||||
// protect against a memory over commitment, for some reason -1 hitpoints
|
||||
// cause a segmentation fault. Not in the mood to figure out the exact cause.
|
||||
// If -1 hitpoints are send we crash :/
|
||||
// Protect against a memory over commitment:
|
||||
//! @todo Not in the mood to figure out the exact cause:
|
||||
// For some reason -1 hitpoints cause a segmentation fault.
|
||||
// If -1 hitpoints are sent, we crash :/
|
||||
try {
|
||||
consider_combat_ = true;
|
||||
game_events::fire("ai turn");
|
||||
do_move();
|
||||
} catch(std::bad_alloc) {
|
||||
lg::wml_error << "Memory exhausted a unit has either a lot hitpoints or a negative amount.\n";
|
||||
lg::wml_error << "Memory exhausted - a unit has either a lot of hitpoints or a negative amount.\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -858,7 +865,7 @@ void ai::do_move()
|
|||
}
|
||||
}
|
||||
|
||||
//execute gotos - first collect gotos in a list
|
||||
// Execute goto-movements - first collect gotos in a list
|
||||
std::vector<gamemap::location> gotos;
|
||||
|
||||
for(unit_map::iterator ui = units_.begin(); ui != units_.end(); ++ui) {
|
||||
|
@ -956,7 +963,7 @@ void ai::do_move()
|
|||
|
||||
LOG_AI << "leader/recruitment phase\n";
|
||||
|
||||
//recruitment phase and leader movement phase
|
||||
// Recruitment phase and leader movement phase.
|
||||
if(leader != units_.end()) {
|
||||
|
||||
if(!passive_leader) {
|
||||
|
@ -1023,7 +1030,7 @@ bool ai::do_combat(std::map<gamemap::location,paths>& possible_moves, const move
|
|||
location to = choice_it->movements[0].second;
|
||||
location target_loc = choice_it->target;
|
||||
|
||||
// never used
|
||||
// Never used:
|
||||
// const unit_map::const_iterator tgt = units_.find(target_loc);
|
||||
|
||||
const location arrived_at = move_unit(from,to,possible_moves);
|
||||
|
@ -1041,8 +1048,8 @@ bool ai::do_combat(std::map<gamemap::location,paths>& possible_moves, const move
|
|||
attack_enemy(to, target_loc, bc.get_attacker_stats().attack_num,
|
||||
bc.get_defender_stats().attack_num);
|
||||
|
||||
//if this is the only unit in the attack, and the target
|
||||
//is still alive, then also summon reinforcements
|
||||
// If this is the only unit in the attack, and the target
|
||||
// is still alive, then also summon reinforcements
|
||||
if(choice_it->movements.size() == 1 && units_.count(target_loc)) {
|
||||
add_target(target(target_loc,3.0,target::BATTLE_AID));
|
||||
}
|
||||
|
@ -1056,7 +1063,7 @@ bool ai::do_combat(std::map<gamemap::location,paths>& possible_moves, const move
|
|||
|
||||
void ai_interface::attack_enemy(const location& u, const location& target, int weapon, int def_weapon)
|
||||
{
|
||||
//stop the user from issuing any commands while the unit is attacking
|
||||
// Stop the user from issuing any commands while the unit is attacking
|
||||
const events::command_disabler disable_commands;
|
||||
|
||||
if(info_.units.count(u) && info_.units.count(target)) {
|
||||
|
@ -1125,8 +1132,9 @@ std::vector<std::pair<gamemap::location,gamemap::location> > ai::get_village_com
|
|||
possible_moves, srcdst, dstsrc, enemy_srcdst, enemy_dstsrc, leader,
|
||||
taken_villages, moved_units, village_moves, i+1);
|
||||
|
||||
//the result is better if it results in getting more villages, or if it results in the same number of villages,
|
||||
//but the leader ends closer to their keep
|
||||
// The result is better if it results in getting more villages,
|
||||
// or if it results in the same number of villages,
|
||||
// but the leader ends closer to their keep.
|
||||
const bool result_better = res.size() >= result.size() ||
|
||||
res.size()+1 == result.size() &&
|
||||
distance != -1 &&
|
||||
|
@ -1163,8 +1171,10 @@ bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves,
|
|||
|
||||
std::map<location,double> vulnerability;
|
||||
|
||||
//we want to build up a list of possible moves we can make that will capture villages.
|
||||
//limit the moves to 'max_village_moves' to make sure things don't get out of hand.
|
||||
// We want to build up a list of possible moves we can make
|
||||
// that will capture villages.
|
||||
// Limit the moves to 'max_village_moves' to make sure
|
||||
// things don't get out of hand.
|
||||
const size_t max_village_moves = 50;
|
||||
std::vector<std::pair<location,location> > village_moves;
|
||||
for(move_map::const_iterator j = dstsrc.begin();
|
||||
|
@ -1190,14 +1200,15 @@ bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves,
|
|||
continue;
|
||||
}
|
||||
|
||||
//if it's a neutral village, and we have no leader, then the village is no use to us,
|
||||
//and we don't want it.
|
||||
// If it is a neutral village, and we have no leader,
|
||||
// then the village is of no use to us, and we don't want it.
|
||||
if(!owned && leader == units_.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//if we have a decent amount of gold, and the leader can't access the keep this turn if they get this village
|
||||
//then don't get this village with them
|
||||
// If we have a decent amount of gold, and the leader can't access
|
||||
// the keep this turn if they get this village,
|
||||
// then don't get this village with them.
|
||||
if(want_village &&
|
||||
leader != units_.end() &&
|
||||
current_team().gold() > 20 &&
|
||||
|
@ -1238,8 +1249,8 @@ bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves,
|
|||
|
||||
LOG_AI << "get_villages() done: " << (SDL_GetTicks() - ticks) << "\n";
|
||||
|
||||
//move all the units to get villages, however move the leader last, so that the castle will be cleared
|
||||
//if it wants to stop to recruit along the way.
|
||||
// Move all the units to get villages, however move the leader last,
|
||||
// so that the castle will be cleared if it wants to stop to recruit along the way.
|
||||
std::pair<location,location> leader_move;
|
||||
|
||||
int moves_made = 0;
|
||||
|
@ -1254,7 +1265,7 @@ bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves,
|
|||
++moves_made;
|
||||
leader = find_leader(units_, team_num_);
|
||||
|
||||
//if we didn't make it to the destination, it means we were ambushed.
|
||||
// If we didn't make it to the destination, it means we were ambushed.
|
||||
if(loc != i->first) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1284,19 +1295,19 @@ bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves,
|
|||
bool ai::get_healing(std::map<gamemap::location,paths>& possible_moves,
|
||||
const move_map& srcdst, const move_map& enemy_dstsrc)
|
||||
{
|
||||
//find units in need of healing
|
||||
// Find units in need of healing.
|
||||
unit_map::iterator u_it = units_.begin();
|
||||
for(; u_it != units_.end(); ++u_it) {
|
||||
unit& u = u_it->second;
|
||||
|
||||
//if the unit is on our side, has lost as many or more than 1/2 round
|
||||
//worth of healing, and doesn't regenerate itself, then try to
|
||||
//find a vacant village for it to rest in
|
||||
// If the unit is on our side, has lost as many or more than
|
||||
// 1/2 round worth of healing, and doesn't regenerate itself,
|
||||
// then try to find a vacant village for it to rest in.
|
||||
if(u.side() == team_num_ &&
|
||||
u.max_hitpoints() - u.hitpoints() >= game_config::poison_amount/2 &&
|
||||
!u.get_ability_bool("regenerate",u_it->first)) {
|
||||
|
||||
//look for the village which is the least vulnerable to enemy attack
|
||||
// Look for the village which is the least vulnerable to enemy attack.
|
||||
typedef std::multimap<location,location>::const_iterator Itor;
|
||||
std::pair<Itor,Itor> it = srcdst.equal_range(u_it->first);
|
||||
double best_vulnerability = 100000.0;
|
||||
|
@ -1316,7 +1327,7 @@ bool ai::get_healing(std::map<gamemap::location,paths>& possible_moves,
|
|||
++it.first;
|
||||
}
|
||||
|
||||
//if we have found an eligible village
|
||||
// If we have found an eligible village:
|
||||
if(best_loc != it.second) {
|
||||
const location& src = best_loc->first;
|
||||
const location& dst = best_loc->second;
|
||||
|
@ -1345,7 +1356,8 @@ bool ai::should_retreat(const gamemap::location& loc, const unit_map::const_iter
|
|||
const double proposed_terrain =
|
||||
un->second.defense_modifier(map_.get_terrain(loc))/100.0;
|
||||
|
||||
//the 'exposure' is the additional % chance to hit this unit receives from being on a sub-optimal defensive terrain
|
||||
// The 'exposure' is the additional % chance to hit
|
||||
// this unit receives from being on a sub-optimal defensive terrain.
|
||||
const double exposure = proposed_terrain - optimal_terrain;
|
||||
|
||||
const double our_power = power_projection(loc,dstsrc);
|
||||
|
@ -1357,7 +1369,7 @@ bool ai::retreat_units(std::map<gamemap::location,paths>& possible_moves,
|
|||
const move_map& srcdst, const move_map& dstsrc,
|
||||
const move_map& enemy_dstsrc, unit_map::const_iterator leader)
|
||||
{
|
||||
//get versions of the move map that assume that all units are at full movement
|
||||
// Get versions of the move map that assume that all units are at full movement
|
||||
std::map<gamemap::location,paths> dummy_possible_moves;
|
||||
move_map fullmove_srcdst;
|
||||
move_map fullmove_dstsrc;
|
||||
|
@ -1375,16 +1387,18 @@ bool ai::retreat_units(std::map<gamemap::location,paths>& possible_moves,
|
|||
unit_map::const_iterator(i) != leader &&
|
||||
!i->second.incapacitated()) {
|
||||
|
||||
//this unit still has movement left, and is a candidate to retreat. We see the amount
|
||||
//of power of each side on the situation, and decide whether it should retreat.
|
||||
// This unit still has movement left, and is a candidate to retreat.
|
||||
// We see the amount of power of each side on the situation,
|
||||
// and decide whether it should retreat.
|
||||
if(should_retreat(i->first, i, fullmove_srcdst, fullmove_dstsrc,
|
||||
enemy_dstsrc, current_team().caution())) {
|
||||
|
||||
bool can_reach_leader = false;
|
||||
|
||||
//time to retreat. Look for the place where the power balance is most in our favor.
|
||||
//If we can't find anywhere where we like the power balance, just try to
|
||||
//get to the best defensive hex
|
||||
// Time to retreat. Look for the place where the power balance
|
||||
// is most in our favor.
|
||||
// If we can't find anywhere where we like the power balance,
|
||||
// just try to get to the best defensive hex.
|
||||
typedef move_map::const_iterator Itor;
|
||||
std::pair<Itor,Itor> itors = srcdst.equal_range(i->first);
|
||||
gamemap::location best_pos, best_defensive(i->first);
|
||||
|
@ -1400,9 +1414,9 @@ bool ai::retreat_units(std::map<gamemap::location,paths>& possible_moves,
|
|||
break;
|
||||
}
|
||||
|
||||
//we rate the power balance of a hex based on our power projection compared
|
||||
//to theirs, multiplying their power projection by their chance to hit us
|
||||
//on the hex we're planning to flee to.
|
||||
// We rate the power balance of a hex based on our power projection
|
||||
// compared to theirs, multiplying their power projection by their
|
||||
// chance to hit us on the hex we're planning to flee to.
|
||||
const gamemap::location& hex = itors.first->second;
|
||||
const int defense = i->second.defense_modifier(map_.get_terrain(hex));
|
||||
const double our_power = power_projection(hex,dstsrc);
|
||||
|
@ -1413,7 +1427,7 @@ bool ai::retreat_units(std::map<gamemap::location,paths>& possible_moves,
|
|||
best_rating = rating;
|
||||
}
|
||||
|
||||
//give a bonus for getting to a village.
|
||||
// Give a bonus for getting to a village.
|
||||
const int modified_defense = defense - (map_.is_village(hex) ? 10 : 0);
|
||||
|
||||
if(modified_defense < best_defensive_rating) {
|
||||
|
@ -1424,8 +1438,8 @@ bool ai::retreat_units(std::map<gamemap::location,paths>& possible_moves,
|
|||
++itors.first;
|
||||
}
|
||||
|
||||
//if the unit is in range of its leader, it should never retreat --
|
||||
//it has to defend the leader instead
|
||||
// If the unit is in range of its leader, it should
|
||||
// never retreat -- it has to defend the leader instead.
|
||||
if(can_reach_leader) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1492,8 +1506,9 @@ bool ai::move_to_targets(std::map<gamemap::location, paths>& possible_moves,
|
|||
|
||||
const location arrived_at = move_unit(move.first,move.second,possible_moves);
|
||||
|
||||
//we didn't arrive at our intended destination. We return true, meaning that
|
||||
//the AI algorithm should be recalculated from the start.
|
||||
// We didn't arrive at our intended destination.
|
||||
// We return true, meaning that the AI algorithm
|
||||
// should be recalculated from the start.
|
||||
if(arrived_at != move.second) {
|
||||
LOG_STREAM(warn, ai) << "didn't arrive at destination\n";
|
||||
return true;
|
||||
|
@ -1504,8 +1519,8 @@ bool ai::move_to_targets(std::map<gamemap::location, paths>& possible_moves,
|
|||
if (u_it == units_.end() || u_it->second.incapacitated()) {
|
||||
LOG_STREAM(warn, ai) << "stolen or incapacitated\n";
|
||||
} else {
|
||||
//search to see if there are any enemy units next
|
||||
//to the tile which really should be attacked now the move is done.
|
||||
// Search to see if there are any enemy units next to the tile
|
||||
// which really should be attacked now the move is done.
|
||||
gamemap::location adj[6];
|
||||
get_adjacent_tiles(arrived_at,adj);
|
||||
gamemap::location target;
|
||||
|
@ -1517,7 +1532,7 @@ bool ai::move_to_targets(std::map<gamemap::location, paths>& possible_moves,
|
|||
|
||||
if(enemy != units_.end() &&
|
||||
current_team().is_enemy(enemy->second.side()) && !enemy->second.incapacitated()) {
|
||||
//current behavior is to only make risk-free attacks
|
||||
// Current behavior is to only make risk-free attacks.
|
||||
battle_context bc(map_, teams_, units_, state_, gameinfo_, arrived_at, adj[n], -1, -1, 100.0);
|
||||
if (bc.get_defender_stats().damage == 0) {
|
||||
attack_enemy(arrived_at, adj[n], bc.get_attacker_stats().attack_num,
|
||||
|
@ -1528,8 +1543,8 @@ bool ai::move_to_targets(std::map<gamemap::location, paths>& possible_moves,
|
|||
}
|
||||
}
|
||||
|
||||
//don't allow any other units to move onto the tile our unit
|
||||
//just moved onto
|
||||
// Don't allow any other units to move onto the tile
|
||||
// our unit just moved onto
|
||||
typedef move_map::iterator Itor;
|
||||
std::pair<Itor,Itor> del = dstsrc.equal_range(arrived_at);
|
||||
dstsrc.erase(del.first,del.second);
|
||||
|
@ -1555,9 +1570,9 @@ int ai::average_resistance_against(const unit_type& a, const unit_type& b) const
|
|||
}
|
||||
|
||||
if (weighting_sum == 0) {
|
||||
// This unit can't move on this map so just get the avarage weighted of all
|
||||
// available terrains. This still is a kind of silly since the opponent
|
||||
// probably can't recruit this unit and it's a static unit.
|
||||
// This unit can't move on this map, so just get the average weighted
|
||||
// of all available terrains. This still is a kind of silly
|
||||
// since the opponent probably can't recruit this unit and it's a static unit.
|
||||
for (std::map<t_translation::t_letter, size_t>::const_iterator jj = terrain.begin(),
|
||||
jj_end = terrain.end(); jj != jj_end; ++jj)
|
||||
{
|
||||
|
@ -1596,17 +1611,17 @@ int ai::average_resistance_against(const unit_type& a, const unit_type& b) const
|
|||
prob = prob * (100 - cth) / 100;
|
||||
// Assume poison works one turn.
|
||||
int poison_damage = game_config::poison_amount * (10000 - prob);
|
||||
// As poison works irrespective of the resistance, its relative
|
||||
// damage (and hence weight) is "poison_damage / (cth * resistance)".
|
||||
// As poison works irrespective of the resistance, its relative damage
|
||||
// (and hence weight) is "poison_damage / (cth * resistance)".
|
||||
sum += poison_damage;
|
||||
weight_sum += poison_damage / (cth * resistance);
|
||||
}
|
||||
}
|
||||
|
||||
// catch division by zero here if the attacking unit
|
||||
// has zero attacks and/or zero damage
|
||||
// if it has no attack at all the ai shouldn't prefer
|
||||
// that unit anyway
|
||||
// Catch division by zero here if the attacking unit
|
||||
// has zero attacks and/or zero damage.
|
||||
// If it has no attack at all, the ai shouldn't prefer
|
||||
// that unit anyway.
|
||||
if (weight_sum == 0) {
|
||||
return sum;
|
||||
}
|
||||
|
@ -1633,7 +1648,7 @@ void ai::analyze_potential_recruit_combat()
|
|||
|
||||
log_scope2(ai, "analyze_potential_recruit_combat()");
|
||||
|
||||
//records the best combat analysis for each usage type
|
||||
// Records the best combat analysis for each usage type.
|
||||
std::map<std::string,int> best_usage;
|
||||
|
||||
const std::set<std::string>& recruits = current_team().recruits();
|
||||
|
@ -1671,8 +1686,9 @@ void ai::analyze_potential_recruit_combat()
|
|||
}
|
||||
}
|
||||
|
||||
//recommend not to use units of a certain usage type if they have a score more than 1000
|
||||
//below the best unit of that usage type
|
||||
// Recommend not to use units of a certain usage type
|
||||
// if they have a score more than 1000 below
|
||||
// the best unit of that usage type.
|
||||
for(i = recruits.begin(); i != recruits.end(); ++i) {
|
||||
const game_data::unit_type_map::const_iterator info = gameinfo_.unit_types.find(*i);
|
||||
if(info == gameinfo_.unit_types.end() || not_recommended_units_.count(*i)) {
|
||||
|
@ -1823,8 +1839,9 @@ void ai::do_recruitment()
|
|||
|
||||
size_t neutral_villages = 0;
|
||||
|
||||
//we recruit the initial allocation of scouts based on how many neutral villages
|
||||
//there are that are closer to us than to other keeps.
|
||||
// We recruit the initial allocation of scouts
|
||||
// based on how many neutral villages there are
|
||||
// that are closer to us than to other keeps.
|
||||
const std::vector<location>& villages = map_.villages();
|
||||
for(std::vector<location>::const_iterator v = villages.begin(); v != villages.end(); ++v) {
|
||||
const int owner = village_owner(*v,teams_);
|
||||
|
@ -1847,12 +1864,13 @@ void ai::do_recruitment()
|
|||
}
|
||||
}
|
||||
|
||||
//the villages per scout is for a two-side battle, accounting for all neutral villages
|
||||
//on the map. We only look at villages closer to us, so we halve it, making us get
|
||||
//twice as many scouts
|
||||
// The villages per scout is for a two-side battle,
|
||||
// accounting for all neutral villages on the map.
|
||||
// We only look at villages closer to us, so we halve it,
|
||||
// making us get twice as many scouts.
|
||||
const int villages_per_scout = current_team().villages_per_scout()/2;
|
||||
|
||||
//get scouts depending on how many neutral villages there are
|
||||
// Get scouts depending on how many neutral villages there are.
|
||||
int scouts_wanted = villages_per_scout > 0 ? neutral_villages/villages_per_scout : 0;
|
||||
|
||||
LOG_AI << "scouts_wanted: " << neutral_villages << "/"
|
||||
|
@ -1883,7 +1901,7 @@ void ai::do_recruitment()
|
|||
return;
|
||||
}
|
||||
|
||||
//buy units as long as we have room and can afford it
|
||||
// Buy units as long as we have room and can afford it.
|
||||
while(recruit_usage(options[rand()%options.size()])) {
|
||||
}
|
||||
}
|
||||
|
@ -1950,7 +1968,7 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
|||
return;
|
||||
}
|
||||
|
||||
//find where the leader can move
|
||||
// Find where the leader can move
|
||||
const paths leader_paths(map_, state_, gameinfo_, units_, leader->first,
|
||||
teams_, false, false, current_team());
|
||||
const gamemap::location& start_pos = nearest_keep(leader->first);
|
||||
|
@ -1958,18 +1976,18 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
|||
std::map<gamemap::location,paths> possible_moves;
|
||||
possible_moves.insert(std::pair<gamemap::location,paths>(leader->first,leader_paths));
|
||||
|
||||
//if the leader is not on his starting location, move him there.
|
||||
// If the leader is not on his starting location, move him there.
|
||||
if(leader->first != start_pos) {
|
||||
const paths::routes_map::const_iterator itor = leader_paths.routes.find(start_pos);
|
||||
if(itor != leader_paths.routes.end() && units_.count(start_pos) == 0) {
|
||||
move_unit(leader->first,start_pos,possible_moves);
|
||||
} else {
|
||||
//make a map of the possible locations the leader can move to, ordered by the
|
||||
//distance from the keep
|
||||
// Make a map of the possible locations the leader can move to,
|
||||
// ordered by the distance from the keep.
|
||||
std::multimap<int,gamemap::location> moves_toward_keep;
|
||||
|
||||
//the leader can't move to his keep, try to move to the closest location to
|
||||
//the keep where there are no enemies in range.
|
||||
// The leader can't move to his keep, try to move to the closest location
|
||||
// to the keep where there are no enemies in range.
|
||||
const int current_distance = distance_between(leader->first,start_pos);
|
||||
for(paths::routes_map::const_iterator i = leader_paths.routes.begin();
|
||||
i != leader_paths.routes.end(); ++i) {
|
||||
|
@ -1980,7 +1998,8 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
|||
}
|
||||
}
|
||||
|
||||
//find the first location which we can move to without the threat of enemies
|
||||
// Find the first location which we can move to,
|
||||
// without the threat of enemies.
|
||||
for(std::multimap<int,gamemap::location>::const_iterator j = moves_toward_keep.begin();
|
||||
j != moves_toward_keep.end(); ++j) {
|
||||
|
||||
|
@ -2010,11 +2029,11 @@ void ai::move_leader_after_recruit(const move_map& /*srcdst*/,
|
|||
possible_moves.insert(std::pair<gamemap::location,paths>(leader->first,leader_paths));
|
||||
|
||||
if(current_team().gold() < 20 && is_accessible(leader->first,enemy_dstsrc) == false) {
|
||||
//see if we want to ward any enemy units off from getting our villages
|
||||
// See if we want to ward any enemy units off from getting our villages.
|
||||
for(move_map::const_iterator i = enemy_dstsrc.begin(); i != enemy_dstsrc.end(); ++i) {
|
||||
|
||||
//if this is a village of ours, that an enemy can capture on their turn, and
|
||||
//which we might be able to reach in two turns.
|
||||
// If this is a village of ours, that an enemy can capture
|
||||
// on their turn, and which we might be able to reach in two turns.
|
||||
if(map_.is_village(i->first) && current_team().owns_village(i->first) &&
|
||||
int(distance_between(i->first,leader->first)) <= leader->second.total_movement()*2) {
|
||||
|
||||
|
@ -2031,7 +2050,8 @@ void ai::move_leader_after_recruit(const move_map& /*srcdst*/,
|
|||
}
|
||||
}
|
||||
|
||||
//if this location is in range of the village, then we consider it
|
||||
// If this location is in range of the village,
|
||||
// then we consider moving to it
|
||||
if(current_loc.valid()) {
|
||||
LOG_AI << "considering movement to " << str_cast(current_loc.x + 1)
|
||||
<< "," << str_cast(current_loc.y+1);
|
||||
|
@ -2047,8 +2067,8 @@ void ai::move_leader_after_recruit(const move_map& /*srcdst*/,
|
|||
}
|
||||
}
|
||||
|
||||
//see if any friendly leaders can make it to our keep. If they can, then move off it so that they
|
||||
//can recruit if they want.
|
||||
// See if any friendly leaders can make it to our keep.
|
||||
// If they can, then move off it, so that they can recruit if they want.
|
||||
if(nearest_keep(leader->first) == leader->first) {
|
||||
const location keep = leader->first;
|
||||
std::pair<gamemap::location,unit> *temp_leader;
|
||||
|
@ -2073,11 +2093,12 @@ void ai::move_leader_after_recruit(const move_map& /*srcdst*/,
|
|||
units_.add(temp_leader);
|
||||
|
||||
if(friend_can_reach_keep) {
|
||||
//find a location for our leader to vacate the keep to
|
||||
// Find a location for our leader to vacate the keep to
|
||||
location adj[6];
|
||||
get_adjacent_tiles(keep,adj);
|
||||
for(size_t n = 0; n != 6; ++n) {
|
||||
//vacate to the first location found that is on the board, our leader can move to, and no enemies can reach
|
||||
// Vacate to the first location found that is on the board,
|
||||
// our leader can move to, and no enemies can reach.
|
||||
if(map_.on_board(adj[n]) &&
|
||||
leader_paths.routes.count(adj[n]) != 0 &&
|
||||
is_accessible(adj[n],enemy_dstsrc) == false) {
|
||||
|
@ -2119,7 +2140,7 @@ bool ai::leader_can_reach_keep()
|
|||
return true;
|
||||
}
|
||||
|
||||
//find where the leader can move
|
||||
// Find where the leader can move
|
||||
const paths leader_paths(map_,state_,gameinfo_,units_,leader->first,teams_,false,false,current_team());
|
||||
|
||||
|
||||
|
@ -2219,7 +2240,8 @@ bool ai::is_accessible(const location& loc, const move_map& dstsrc) const
|
|||
const std::set<gamemap::location>& ai::keeps()
|
||||
{
|
||||
if(keeps_.empty()) {
|
||||
//generate the list of keeps -- iterate over the entire map and find all keeps
|
||||
// Generate the list of keeps:
|
||||
// iterate over the entire map and find all keeps.
|
||||
for(size_t x = 0; x != size_t(map_.w()); ++x) {
|
||||
for(size_t y = 0; y != size_t(map_.h()); ++y) {
|
||||
const gamemap::location loc(x,y);
|
||||
|
|
117
src/ai.hpp
117
src/ai.hpp
|
@ -11,6 +11,10 @@
|
|||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
//! @file ai.hpp
|
||||
//!
|
||||
|
||||
#ifndef AI_HPP_INCLUDED
|
||||
#define AI_HPP_INCLUDED
|
||||
|
||||
|
@ -51,7 +55,7 @@ public:
|
|||
|
||||
bool leader_can_reach_keep();
|
||||
|
||||
//function which will return true iff there has been another attack this turn 'close' to this one
|
||||
//! Return true iff there has been another attack this turn 'close' to this one.
|
||||
bool attack_close(const location& loc) const;
|
||||
|
||||
protected:
|
||||
|
@ -95,13 +99,12 @@ protected:
|
|||
|
||||
void remove_unit_from_moves(const gamemap::location& u, move_map& srcdst, move_map& dstsrc);
|
||||
|
||||
//a function which will find enemy units that threaten our valuable assets
|
||||
//! Find enemy units that threaten our valuable assets.
|
||||
void find_threats();
|
||||
|
||||
bool threats_found_;
|
||||
|
||||
//function which will calculate which movements should
|
||||
//be made to get an optimal number of villages
|
||||
//! Calculate which movements should be made to get an optimal number of villages.
|
||||
std::vector<std::pair<gamemap::location,gamemap::location> > get_village_combinations(
|
||||
std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst,
|
||||
const move_map& dstsrc, const move_map& enemy_srcdst,
|
||||
|
@ -111,17 +114,17 @@ protected:
|
|||
std::vector<std::pair<gamemap::location,gamemap::location> >::const_iterator start_at);
|
||||
|
||||
|
||||
//our own version of 'move_unit'. It is like the version in ai_interface,
|
||||
//however if it is the leader moving, it will first attempt recruitment.
|
||||
//! Our own version of 'move_unit'. It is like the version in ai_interface,
|
||||
//! however if it is the leader moving, it will first attempt recruitment.
|
||||
location move_unit(location from, location to, std::map<location,paths>& possible_moves);
|
||||
|
||||
//our own version of 'attack_enemy'. We record all attacks to support group attacking
|
||||
//! Our own version of 'attack_enemy'. We record all attacks to support group attacking.
|
||||
void attack_enemy(const location& attacking_unit, const location& target,
|
||||
int att_weapon, int def_weapon);
|
||||
|
||||
std::set<location> attacks_;
|
||||
|
||||
//sees if it's possible for a unit to move 'from' -> 'via' -> 'to' all in one turn
|
||||
//! Sees if it's possible for a unit to move 'from' -> 'via' -> 'to' all in one turn.
|
||||
bool multistep_move_possible(location from, location to, location via,
|
||||
std::map<location,paths>& possible_moves);
|
||||
|
||||
|
@ -139,45 +142,45 @@ protected:
|
|||
gamemap::location target;
|
||||
std::vector<std::pair<gamemap::location,gamemap::location> > movements;
|
||||
|
||||
//the value of the unit being targeted
|
||||
//! The value of the unit being targeted.
|
||||
double target_value;
|
||||
|
||||
//the value on average, of units lost in the combat
|
||||
//! The value on average, of units lost in the combat
|
||||
double avg_losses;
|
||||
|
||||
//estimated % chance to kill the unit
|
||||
//! Estimated % chance to kill the unit
|
||||
double chance_to_kill;
|
||||
|
||||
//the average hitpoints damage inflicted
|
||||
//! The average hitpoints damage inflicted
|
||||
double avg_damage_inflicted;
|
||||
|
||||
int target_starting_damage;
|
||||
|
||||
//the average hitpoints damage taken
|
||||
//! The average hitpoints damage taken
|
||||
double avg_damage_taken;
|
||||
|
||||
//the sum of the values of units used in the attack
|
||||
//! The sum of the values of units used in the attack
|
||||
double resources_used;
|
||||
|
||||
//the weighted average of the % chance to hit each attacking unit
|
||||
//! The weighted average of the % chance to hit each attacking unit
|
||||
double terrain_quality;
|
||||
|
||||
//the weighted average of the % defense of the best possible terrain
|
||||
//that the attacking units could reach this turn, without attacking
|
||||
//(good for comparison to see just how good/bad 'terrain_quality' is)
|
||||
//! The weighted average of the % defense of the best possible terrain
|
||||
//! that the attacking units could reach this turn, without attacking
|
||||
//! (good for comparison to see just how good/bad 'terrain_quality' is).
|
||||
double alternative_terrain_quality;
|
||||
|
||||
//the vulnerability is the power projection of enemy units onto the hex
|
||||
//we're standing on. support is the power projection of friendly units.
|
||||
//! The vulnerability is the power projection of enemy units onto the hex
|
||||
//! we're standing on. support is the power projection of friendly units.
|
||||
double vulnerability, support;
|
||||
|
||||
//is true if the unit is a threat to our leader
|
||||
//! Is true if the unit is a threat to our leader.
|
||||
bool leader_threat;
|
||||
|
||||
//is true if this attack sequence makes use of the leader
|
||||
//! Is true if this attack sequence makes use of the leader.
|
||||
bool uses_leader;
|
||||
|
||||
//is true if the units involved in this attack sequence are surrounded.
|
||||
//! Is true if the units involved in this attack sequence are surrounded.
|
||||
bool is_surrounded;
|
||||
};
|
||||
|
||||
|
@ -193,13 +196,15 @@ protected:
|
|||
);
|
||||
|
||||
|
||||
//function which finds how much 'power' a side can attack a certain location with. This is basically
|
||||
//the maximum hp of damage that can be inflicted upon a unit on loc by full-health units, multiplied by
|
||||
//the defense these units will have. (if 'use_terrain' is false, then it will be multiplied by 0.5)
|
||||
//! Function which finds how much 'power' a side can attack a certain location with.
|
||||
//! This is basically the maximum hp of damage that can be inflicted upon a unit on loc
|
||||
//! by full-health units, multiplied by the defense these units will have.
|
||||
//! (if 'use_terrain' is false, then it will be multiplied by 0.5)
|
||||
//
|
||||
//Example: 'loc' can be reached by two units, one of whom has a 10-3 attack and has 48/48 hp, and
|
||||
//can defend at 40% on the adjacent grassland. The other has a 8-2 attack, and has 30/40 hp, and
|
||||
//can defend at 60% on the adjacent mountain. The rating will be 10*3*1.0*0.4 + 8*2*0.75*0.6 = 19.2
|
||||
// Example: 'loc' can be reached by two units, one of whom has a 10-3 attack
|
||||
// and has 48/48 hp, and can defend at 40% on the adjacent grassland.
|
||||
// The other has a 8-2 attack, and has 30/40 hp, and can defend at 60% on the adjacent mountain.
|
||||
// The rating will be 10*3*1.0*0.4 + 8*2*0.75*0.6 = 19.2
|
||||
virtual double power_projection(const gamemap::location& loc, const move_map& dstsrc,
|
||||
bool use_terrain=true) const;
|
||||
|
||||
|
@ -213,13 +218,13 @@ protected:
|
|||
virtual std::vector<target> find_targets(unit_map::const_iterator leader,
|
||||
const move_map& enemy_dstsrc);
|
||||
|
||||
//function to form a group of units suitable for moving along the route, 'route'.
|
||||
//returns the location which the group may reach this turn.
|
||||
//stores the locations of the units in the group in 'units'
|
||||
//! Function to form a group of units suitable for moving along the route, 'route'.
|
||||
//! Returns the location which the group may reach this turn.
|
||||
//! Stores the locations of the units in the group in 'units'
|
||||
virtual location form_group(const std::vector<location>& route,
|
||||
const move_map& dstsrc, std::set<location>& units);
|
||||
|
||||
//function to return the group of enemies that threaten a certain path
|
||||
//! Return the group of enemies that threaten a certain path.
|
||||
virtual void enemies_along_path(const std::vector<location>& route,
|
||||
const move_map& dstsrc, std::set<location>& units);
|
||||
|
||||
|
@ -236,7 +241,7 @@ protected:
|
|||
virtual std::pair<location,location> choose_move(std::vector<target>& targets,
|
||||
const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_dstsrc);
|
||||
|
||||
//function which rates the value of moving onto certain terrain for a unit
|
||||
//! Rates the value of moving onto certain terrain for a unit.
|
||||
virtual int rate_terrain(const unit& u, const location& loc);
|
||||
|
||||
game_display& disp_;
|
||||
|
@ -251,50 +256,56 @@ protected:
|
|||
|
||||
void add_target(const target& tgt) { additional_targets_.push_back(tgt); }
|
||||
|
||||
//function which will analyze all the units that this side can recruit and rate
|
||||
//their movement types. Ratings will be placed in 'unit_movement_scores_', with
|
||||
//lower scores being better, and the lowest possible rating being '10'.
|
||||
//! Analyze all the units that this side can recruit
|
||||
//! and rate their movement types.
|
||||
//! Ratings will be placed in 'unit_movement_scores_',
|
||||
//! with lower scores being better,
|
||||
//! and the lowest possible rating being '10'.
|
||||
virtual void analyze_potential_recruit_movements();
|
||||
|
||||
std::map<std::string,int> unit_movement_scores_;
|
||||
std::set<std::string> not_recommended_units_;
|
||||
|
||||
//function which will analyze all the units that this side can recruit and rate
|
||||
//their fighting suitability against enemy units. Ratings will be placed in
|
||||
//'unit_combat_scores_' with a '0' rating indicating that the unit is 'average'
|
||||
//against enemy units, negative ratings meaning they are poorly suited, and
|
||||
//positive ratings meaning they are well suited
|
||||
//! Analyze all the units that this side can recruit
|
||||
//! and rate their fighting suitability against enemy units.
|
||||
//! Ratings will be placed in 'unit_combat_scores_',
|
||||
//! with a '0' rating indicating that the unit is 'average' against enemy units,
|
||||
//! negative ratings meaning they are poorly suited,
|
||||
//! and positive ratings meaning they are well suited.
|
||||
virtual void analyze_potential_recruit_combat();
|
||||
|
||||
std::map<std::string,int> unit_combat_scores_;
|
||||
|
||||
//function which rates two unit types for their suitability against each other.
|
||||
//returns 0 if the units are equally matched, a positive number if a is suited
|
||||
//against b, and a negative number if b is suited against a.
|
||||
//! Rates two unit types for their suitability against each other.
|
||||
// Returns 0 if the units are equally matched,
|
||||
// a positive number if a is suited against b,
|
||||
// and a negative number if b is suited against a.
|
||||
virtual int compare_unit_types(const unit_type& a, const unit_type& b) const;
|
||||
|
||||
//function which calculates the average resistance unit type a has against
|
||||
//the attacks of unit type b.
|
||||
//! calculates the average resistance unit type a has
|
||||
//! against the attacks of unit type b.
|
||||
virtual int average_resistance_against(const unit_type& a, const unit_type& b) const;
|
||||
|
||||
//functions to deal with keeps
|
||||
//! Functions to deal with keeps.
|
||||
const std::set<location>& keeps();
|
||||
const location& nearest_keep(const location& loc);
|
||||
|
||||
std::set<location> keeps_;
|
||||
|
||||
//function which, given a unit position, and a position the unit wants to
|
||||
//get to in two turns, will return all possible positions the unit can
|
||||
//move to, that will make the destination position accessible next turn
|
||||
//! Function which, given a unit position,
|
||||
//! and a position the unit wants to get to in two turns,
|
||||
//! will return all possible positions the unit can move to,
|
||||
//! that will make the destination position accessible next turn.
|
||||
void access_points(const move_map& srcdst, const location& u,
|
||||
const location& dst, std::vector<location>& out);
|
||||
|
||||
//function which gets the areas of the map that this AI has been instructed to avoid
|
||||
//! Function which gets the areas of the map
|
||||
//! that this AI has been instructed to avoid.
|
||||
const std::set<location>& avoided_locations();
|
||||
|
||||
std::set<location> avoid_;
|
||||
|
||||
// Weapon choice cache, to speed simulations.
|
||||
//! Weapon choice cache, to speed simulations.
|
||||
std::map<std::pair<location,const unit_type *>,
|
||||
std::pair<battle_context::unit_stats,battle_context::unit_stats> > unit_stats_cache_;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue