Some more improvements to AI movement and attack selection
Fixed team survival AI parameters
This commit is contained in:
parent
ff3b3a3623
commit
89ddafd8c7
5 changed files with 94 additions and 38 deletions
|
@ -379,14 +379,27 @@ usage=mask
|
|||
|
||||
{SIDE_COMPUTER 1 Attacker (_ "Attacker") 1000 47 () (
|
||||
leader_value=7.0
|
||||
aggression=0.95
|
||||
aggression=0.99
|
||||
caution=0.0
|
||||
)}
|
||||
{SIDE_PLAYER 2 Defenders (_ "Defender") 125 -2 ()}
|
||||
{SIDE_PLAYER 3 Defenders (_ "Defender") 125 -2 ()}
|
||||
{SIDE_PLAYER 4 Defenders (_ "Defender") 125 -2 ()}
|
||||
{SIDE_PLAYER 5 Defenders (_ "Defender") 125 -2 ()}
|
||||
{SIDE_PLAYER 6 Defenders (_ "Defender") 125 -2 ()}
|
||||
{SIDE_PLAYER 7 Defenders (_ "Defender") 125 -2 ()}
|
||||
{SIDE_PLAYER 2 Defenders (_ "Defender") 125 -2 ([ai]
|
||||
villages_per_scout=0
|
||||
[/ai])}
|
||||
{SIDE_PLAYER 3 Defenders (_ "Defender") 125 -2 ([ai]
|
||||
villages_per_scout=0
|
||||
[/ai])}
|
||||
{SIDE_PLAYER 4 Defenders (_ "Defender") 125 -2 ([ai]
|
||||
villages_per_scout=0
|
||||
[/ai])}
|
||||
{SIDE_PLAYER 5 Defenders (_ "Defender") 125 -2 ([ai]
|
||||
villages_per_scout=0
|
||||
[/ai])}
|
||||
{SIDE_PLAYER 6 Defenders (_ "Defender") 125 -2 ([ai]
|
||||
villages_per_scout=0
|
||||
[/ai])}
|
||||
{SIDE_PLAYER 7 Defenders (_ "Defender") 125 -2 ([ai]
|
||||
villages_per_scout=0
|
||||
[/ai])}
|
||||
[/multiplayer]
|
||||
|
||||
#undef TS_MAP_DATA
|
||||
|
|
30
src/ai.cpp
30
src/ai.cpp
|
@ -536,7 +536,6 @@ gamemap::location ai_interface::move_unit_partial(location from, location to,
|
|||
}
|
||||
|
||||
if(rt != p.routes.end()) {
|
||||
assert(static_cast<size_t>(u_it->second.movement_left()) >= rt->second.steps.size() && "Trying to move unit without enough move points left\n");
|
||||
u_it->second.set_movement(rt->second.move_left);
|
||||
|
||||
std::vector<location> steps = rt->second.steps;
|
||||
|
@ -981,14 +980,21 @@ void ai::evaluate_recruiting_value(unit_map::iterator leader)
|
|||
}
|
||||
|
||||
float free_slots = 0.0f;
|
||||
const float gold = current_team().gold();
|
||||
const float unit_price = current_team().average_recruit_price();
|
||||
if (map_.is_keep(leader->first))
|
||||
{
|
||||
std::set<gamemap::location> checked_hexes;
|
||||
checked_hexes.insert(leader->first);
|
||||
free_slots = count_free_hexes_in_castle(leader->first, checked_hexes);
|
||||
} else {
|
||||
gamemap::location loc = nearest_keep(leader->first);
|
||||
if (units_.find(loc) == units_.end()
|
||||
&& gold/unit_price > 1.0f)
|
||||
{
|
||||
free_slots -= current_team().num_pos_recruits_to_force();
|
||||
}
|
||||
}
|
||||
const float gold = current_team().gold();
|
||||
const float unit_price = current_team().average_recruit_price();
|
||||
recruiting_prefered_ = (gold/unit_price) - free_slots > current_team().num_pos_recruits_to_force();
|
||||
DBG_AI << "recruiting prefered: " << (recruiting_prefered_?"yes":"no") <<
|
||||
" units to recruit: " << (gold/unit_price) <<
|
||||
|
@ -1132,7 +1138,17 @@ void ai::do_move()
|
|||
if(leader != units_.end()) {
|
||||
|
||||
if(!passive_leader) {
|
||||
gamemap::location before = leader->first;
|
||||
move_leader_to_keep(enemy_dstsrc);
|
||||
leader = find_leader(units_,team_num_);
|
||||
if (leader->first != before
|
||||
&& leader->second.movement_left() > 0
|
||||
&& recruiting_prefered_)
|
||||
{
|
||||
recruiting_prefered_ = 2;
|
||||
do_move();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (map_.is_keep(leader->first))
|
||||
|
@ -1211,7 +1227,7 @@ bool ai::do_combat(std::map<gamemap::location,paths>& possible_moves, const move
|
|||
time_taken = SDL_GetTicks() - ticks;
|
||||
LOG_AI << "analysis took " << time_taken << " ticks\n";
|
||||
|
||||
if(choice_rating > current_team().caution()) {
|
||||
if(choice_rating > current_team().caution()/2) {
|
||||
location from = choice_it->movements[0].first;
|
||||
location to = choice_it->movements[0].second;
|
||||
location target_loc = choice_it->target;
|
||||
|
@ -1322,11 +1338,12 @@ bool ai::get_healing(std::map<gamemap::location,paths>& possible_moves,
|
|||
typedef std::multimap<location,location>::const_iterator Itor;
|
||||
std::pair<Itor,Itor> it = srcdst.equal_range(u_it->first);
|
||||
double best_vulnerability = 100000.0;
|
||||
const double leader_penalty = (u.can_recruit()?2.0:1.0);
|
||||
Itor best_loc = it.second;
|
||||
while(it.first != it.second) {
|
||||
const location& dst = it.first->second;
|
||||
if(map_.gives_healing(dst) && (units_.find(dst) == units_.end() || dst == u_it->first)) {
|
||||
const double vuln = power_projection(it.first->first, enemy_dstsrc);
|
||||
const double vuln = power_projection(it.first->first, enemy_dstsrc)*leader_penalty;
|
||||
LOG_AI << "found village with vulnerability: " << vuln << "\n";
|
||||
if(vuln < best_vulnerability) {
|
||||
best_vulnerability = vuln;
|
||||
|
@ -1339,7 +1356,8 @@ bool ai::get_healing(std::map<gamemap::location,paths>& possible_moves,
|
|||
}
|
||||
|
||||
// If we have found an eligible village:
|
||||
if(best_loc != it.second) {
|
||||
if(best_loc != it.second
|
||||
&& best_vulnerability < u.hitpoints()) {
|
||||
const location& src = best_loc->first;
|
||||
const location& dst = best_loc->second;
|
||||
|
||||
|
|
|
@ -207,22 +207,24 @@ void ai::do_attack_analysis(
|
|||
}
|
||||
|
||||
// See if this position is the best rated we've seen so far.
|
||||
const int rating = rate_terrain(unit_itor->second,tiles[j]) * backstab_bonus;
|
||||
if(cur_position >= 0 && rating < best_rating) {
|
||||
int rating = rate_terrain(unit_itor->second,tiles[j]) * backstab_bonus;
|
||||
if(cur_position >= 0 && rating < best_rating * 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find out how vulnerable we are to attack from enemy units in this hex.
|
||||
const double vulnerability = power_projection(tiles[j],enemy_dstsrc);
|
||||
const double vulnerability = power_projection(tiles[j],enemy_dstsrc)*current_team().caution()*10;
|
||||
|
||||
// Calculate how much support we have on this hex from allies.
|
||||
// Support does not take into account terrain, because we don't want
|
||||
// to move into a hex that is surrounded by good defensive terrain.
|
||||
const double support = power_projection(tiles[j],fullmove_dstsrc,false);
|
||||
const double support = power_projection(tiles[j],fullmove_dstsrc,false)*current_team().aggression();
|
||||
|
||||
// If this is a position with equal defense to another position,
|
||||
// but more vulnerability then we don't want to use it.
|
||||
if(cur_position >= 0 && rating == best_rating && vulnerability/surround_bonus - support*surround_bonus >= best_vulnerability - best_support) {
|
||||
const double leader_penalty = (unit_itor->second.can_recruit()? 1.4:1.0);
|
||||
rating -= ((vulnerability/surround_bonus)*leader_penalty - support*surround_bonus);
|
||||
if(cur_position >= 0 && rating < best_rating) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -822,7 +822,7 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
|||
{
|
||||
// Make a map of the possible locations the leader can move to,
|
||||
// ordered by the distance from the keep.
|
||||
int best_value = INT_MAX;
|
||||
int best_value = INT_MAX - 1;
|
||||
gamemap::location best_target;
|
||||
|
||||
// The leader can't move to his keep, try to move to the closest location
|
||||
|
@ -832,12 +832,16 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
|||
|
||||
const shortest_path_calculator cost_calc(leader->second, current_team(), units_,
|
||||
teams_,map_);
|
||||
|
||||
const double limit = std::min(10000, best_value + 1);
|
||||
paths::routes_map::iterator route = path_itor->second.routes.insert(
|
||||
std::make_pair(*i,
|
||||
a_star_search(leader->first, *i, 10000.0, &cost_calc,map_.w(), map_.h()))).first;
|
||||
a_star_search(leader->first, *i, limit, &cost_calc,map_.w(), map_.h()))).first;
|
||||
if (route->second.steps.empty())
|
||||
{
|
||||
path_itor->second.routes.erase(route);
|
||||
continue;
|
||||
}
|
||||
|
||||
const int distance = route->second.steps.size()-1;
|
||||
std::set<gamemap::location> checked_hexes;
|
||||
checked_hexes.insert(*i);
|
||||
const int free_slots = count_free_hexes_in_castle(*i, checked_hexes);
|
||||
|
@ -851,7 +855,34 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
|||
&& !u->second.invisible(u->first, units_, teams_)
|
||||
?(current_team().is_enemy(u->second.side())?6:3)
|
||||
:0);
|
||||
const int enemy = (power_projection(*i, enemy_dstsrc) * 8 * leader->second.total_movement())/leader->second.hitpoints();
|
||||
const int enemy = (power_projection(*i, enemy_dstsrc) * 15 * leader->second.total_movement())/leader->second.hitpoints();
|
||||
|
||||
int value = empty_slots + enemy + tactical_value + reserved_penalty;
|
||||
|
||||
if (value + static_cast<int>(route->second.steps.size()) - 1 >= best_value)
|
||||
continue;
|
||||
|
||||
route->second.move_left = leader->second.movement_left();
|
||||
int distance = 0;
|
||||
gamemap::location target;
|
||||
std::vector<gamemap::location>::iterator loc;
|
||||
|
||||
for (loc = route->second.steps.begin() + 1;
|
||||
loc != route->second.steps.end();
|
||||
++loc)
|
||||
{
|
||||
distance += leader->second.movement_cost(map_.get_terrain(*loc));
|
||||
if (route->second.move_left == 0)
|
||||
continue;
|
||||
route->second.move_left -= leader->second.movement_cost(map_.get_terrain(*loc));
|
||||
if (route->second.move_left <= 0)
|
||||
{
|
||||
target = *loc;
|
||||
route->second.move_left = 0;
|
||||
}
|
||||
}
|
||||
if (route->second.move_left > 0)
|
||||
target = *(loc-1);
|
||||
|
||||
int multiturn_move_penalty = 0;
|
||||
if (recruiting_prefered_)
|
||||
|
@ -859,20 +890,11 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
|||
|
||||
const int distance_value = (distance > leader->second.movement_left()?
|
||||
((distance - leader->second.movement_left())/leader->second.total_movement()+multiturn_move_penalty)*leader->second.total_movement() : 0);
|
||||
const int value = distance_value + empty_slots + enemy + tactical_value + reserved_penalty;
|
||||
|
||||
if (value > best_value)
|
||||
value += distance_value;
|
||||
|
||||
if (value >= best_value)
|
||||
continue;
|
||||
gamemap::location target;
|
||||
if (distance > leader->second.movement_left())
|
||||
{
|
||||
target = route->second.steps[leader->second.movement_left()];
|
||||
route->second.steps.erase(route->second.steps.begin() + leader->second.movement_left() + 1,route->second.steps.end());
|
||||
route->second.move_left = 0;
|
||||
} else {
|
||||
target = *i;
|
||||
route->second.move_left = leader->second.movement_left() - distance;
|
||||
}
|
||||
|
||||
best_value = value;
|
||||
best_target = target;
|
||||
DBG_AI << "Considiring keep: " << *i <<
|
||||
|
@ -888,7 +910,8 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
|||
}
|
||||
|
||||
// Find the location with the best value
|
||||
if (leader->first != best_target)
|
||||
if (leader->first != best_target
|
||||
&& best_target != gamemap::location::null_location)
|
||||
move_unit(leader->first,best_target,possible_moves);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -344,7 +344,7 @@ void ai::find_villages(
|
|||
}
|
||||
|
||||
const unit& un = u->second;
|
||||
const size_t threat_multipler = (current_loc == leader_loc?2:1) * current_team().caution() * 10;
|
||||
const size_t threat_multipler = (current_loc == leader_loc?4:1) * current_team().caution() * 4;
|
||||
if(un.hitpoints() < (threat_multipler*threat*2*un.defense_modifier(map_.get_terrain(current_loc)))/100) {
|
||||
continue;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue