various AI improvements
This commit is contained in:
parent
aaae03dec2
commit
bf663eb2e2
9 changed files with 79 additions and 27 deletions
|
@ -74,7 +74,8 @@ Defeat:
|
|||
description=Robert
|
||||
side=2
|
||||
canrecruit=1
|
||||
recruit=Cavalry, Swordsman, Mage, Ogre, Duelist
|
||||
recruit=Cavalry,Swordsman,Mage,Ogre,Duelist,Longbowman
|
||||
recruitment_pattern=scout,fighter,fighter,fighter,archer,mixed fighter
|
||||
{GOLD 200 300 500}
|
||||
[/side]
|
||||
|
||||
|
@ -85,6 +86,9 @@ Defeat:
|
|||
canrecruit=1
|
||||
recruit=Gryphon
|
||||
gold=0
|
||||
[ai]
|
||||
passive_leader=yes
|
||||
[/ai]
|
||||
[/side]
|
||||
|
||||
#if the player kills the mother gryphon
|
||||
|
|
|
@ -61,7 +61,7 @@ Defeat:
|
|||
experience=0
|
||||
side=2
|
||||
canrecruit=1
|
||||
recruit=Orcish Grunt,Wolf Rider,Orcish Archer,Troll Whelp
|
||||
recruit=Orcish Grunt,Wolf Rider,Orcish Archer,Troll Whelp,Saurian
|
||||
recruitment_pattern=scout,scout,fighter,fighter,archer
|
||||
{GOLD 80 160 260}
|
||||
enemy=1
|
||||
|
|
47
src/ai.cpp
47
src/ai.cpp
|
@ -71,6 +71,7 @@ bool ai::recruit_usage(const std::string& usage)
|
|||
if(i->second.usage() == usage && recruits.count(name)
|
||||
&& current_team().gold() - i->second.cost() > min_gold
|
||||
&& not_recommended_units_.count(name) == 0) {
|
||||
std::cerr << "recommending '" << name << "'\n";
|
||||
options.push_back(name);
|
||||
}
|
||||
}
|
||||
|
@ -170,6 +171,7 @@ void ai_interface::sync_network()
|
|||
|
||||
gamemap::location ai_interface::move_unit(location from, location to, std::map<location,paths>& possible_moves)
|
||||
{
|
||||
std::cerr << "ai_interface::move_unit " << (from.x+1) << (from.y+1) << " -> " << (to.x+1) << "," << (to.y+1) << "\n";
|
||||
//stop the user from issuing any commands while the unit is moving
|
||||
const command_disabler disable_commands(&info_.disp);
|
||||
|
||||
|
@ -188,6 +190,7 @@ gamemap::location ai_interface::move_unit(location from, location to, std::map<l
|
|||
}
|
||||
|
||||
if(from == to) {
|
||||
std::cerr << "moving unit at " << (from.x+1) << "," << (from.y+1) << " on spot. resetting moves\n";
|
||||
u_it->second.set_movement(0);
|
||||
return to;
|
||||
}
|
||||
|
@ -274,6 +277,7 @@ gamemap::location ai_interface::move_unit(location from, location to, std::map<l
|
|||
|
||||
gamemap::location ai::move_unit(location from, location to, std::map<location,paths>& possible_moves)
|
||||
{
|
||||
std::cerr << "ai::move_unit " << (from.x+1) << (from.y+1) << " -> " << (to.x+1) << "," << (to.y+1) << "\n";
|
||||
std::map<location,paths> temp_possible_moves;
|
||||
std::map<location,paths>* possible_moves_ptr = &possible_moves;
|
||||
|
||||
|
@ -321,6 +325,7 @@ 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()) {
|
||||
std::cerr << "setting temp moves of unit to " << move_left << "\n";
|
||||
itor->second.set_movement(move_left);
|
||||
}
|
||||
|
||||
|
@ -335,7 +340,7 @@ gamemap::location ai::move_unit(location from, location to, std::map<location,pa
|
|||
do_recruitment();
|
||||
}
|
||||
|
||||
if(units_.count(to) == 0) {
|
||||
if(units_.count(to) == 0 || from == to) {
|
||||
return ai_interface::move_unit(from,to,*possible_moves_ptr);
|
||||
} else {
|
||||
return from;
|
||||
|
@ -416,6 +421,18 @@ void ai_interface::calculate_possible_moves(std::map<location,paths>& res, move_
|
|||
}
|
||||
}
|
||||
|
||||
void ai::remove_unit_from_moves(const gamemap::location& loc, move_map& srcdst, move_map& dstsrc)
|
||||
{
|
||||
srcdst.erase(loc);
|
||||
for(move_map::iterator i = dstsrc.begin(); i != dstsrc.end(); ) {
|
||||
if(i->second == loc) {
|
||||
dstsrc.erase(i++);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ai::play_turn()
|
||||
{
|
||||
consider_combat_ = true;
|
||||
|
@ -438,7 +455,12 @@ void ai::do_move()
|
|||
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
|
||||
calculate_possible_moves(enemy_possible_moves,enemy_srcdst,enemy_dstsrc,true);
|
||||
|
||||
const bool passive_leader = current_team().ai_parameters()["passive_leader"] == "yes";
|
||||
|
||||
unit_map::iterator leader = find_leader(units_,team_num_);
|
||||
if(leader != units_.end() && passive_leader) {
|
||||
remove_unit_from_moves(leader->first,srcdst,dstsrc);
|
||||
}
|
||||
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
|
@ -475,27 +497,26 @@ void ai::do_move()
|
|||
}
|
||||
|
||||
if(leader != units_.end()) {
|
||||
srcdst.erase(leader->first);
|
||||
for(move_map::iterator i = dstsrc.begin(); i != dstsrc.end(); ) {
|
||||
if(i->second == leader->first) {
|
||||
dstsrc.erase(i++);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
remove_unit_from_moves(leader->first,srcdst,dstsrc);
|
||||
}
|
||||
|
||||
const bool met_invisible_unit = move_to_targets(possible_moves,srcdst,dstsrc,enemy_srcdst,enemy_dstsrc,leader);
|
||||
if(met_invisible_unit) {
|
||||
std::cerr << "met_invisible_unit\n";
|
||||
do_move();
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << "done move to targets\n";
|
||||
|
||||
//recruitment phase and leader movement phase
|
||||
if(leader != units_.end()) {
|
||||
move_leader_to_keep(enemy_dstsrc);
|
||||
do_recruitment();
|
||||
move_leader_after_recruit(enemy_dstsrc);
|
||||
|
||||
if(!passive_leader) {
|
||||
move_leader_after_recruit(enemy_dstsrc);
|
||||
}
|
||||
}
|
||||
|
||||
recorder.end_turn();
|
||||
|
@ -877,8 +898,9 @@ bool ai::move_to_targets(std::map<gamemap::location,paths>& possible_moves, move
|
|||
assert(map_.on_board(ittg->loc));
|
||||
}
|
||||
|
||||
if(move.first.valid() == false)
|
||||
if(move.first.valid() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::cerr << "move: " << move.first.x << ", " << move.first.y << " - " << move.second.x << ", " << move.second.y << "\n";
|
||||
|
||||
|
@ -909,6 +931,7 @@ bool ai::move_to_targets(std::map<gamemap::location,paths>& possible_moves, move
|
|||
//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) {
|
||||
std::cerr << "didn't arrive at destination\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -921,7 +944,7 @@ bool ai::move_to_targets(std::map<gamemap::location,paths>& possible_moves, move
|
|||
|
||||
//don't allow any other units to move onto the tile our unit
|
||||
//just moved onto
|
||||
typedef std::multimap<location,location>::iterator Itor;
|
||||
typedef move_map::iterator Itor;
|
||||
std::pair<Itor,Itor> del = dstsrc.equal_range(arrived_at);
|
||||
dstsrc.erase(del.first,del.second);
|
||||
}
|
||||
|
|
|
@ -325,6 +325,8 @@ protected:
|
|||
|
||||
virtual bool recruit_usage(const std::string& usage);
|
||||
|
||||
void remove_unit_from_moves(const gamemap::location& u, move_map& srcdst, move_map& dstsrc);
|
||||
|
||||
//function which will 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, const move_map& enemy_dstsrc, unit_map::const_iterator leader,
|
||||
|
@ -382,6 +384,9 @@ protected:
|
|||
|
||||
//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
|
||||
bool uses_leader;
|
||||
};
|
||||
|
||||
virtual void do_attack_analysis(
|
||||
|
|
|
@ -309,6 +309,7 @@ void ai::attack_analysis::analyze(const gamemap& map,
|
|||
}
|
||||
|
||||
leader_threat = (tile != 6);
|
||||
uses_leader = false;
|
||||
|
||||
target_value = defend_it->second.type().cost();
|
||||
target_value += (double(defend_it->second.experience())/
|
||||
|
@ -359,6 +360,10 @@ void ai::attack_analysis::analyze(const gamemap& map,
|
|||
unit_map::const_iterator att = units.find(movements[i].first);
|
||||
double cost = att->second.type().cost();
|
||||
|
||||
if(att->second.can_recruit()) {
|
||||
uses_leader = true;
|
||||
}
|
||||
|
||||
const bool on_village = map.is_village(movements[i].second);
|
||||
|
||||
//up to double the value of a unit based on experience
|
||||
|
@ -472,6 +477,12 @@ double ai::attack_analysis::rating(double aggression) const
|
|||
aggression = 1.0;
|
||||
}
|
||||
|
||||
//only use the leader if we do a serious amount of damage
|
||||
//compared to how much they do to us.
|
||||
if(uses_leader && aggression > -1.0) {
|
||||
aggression = -1.0;
|
||||
}
|
||||
|
||||
double value = chance_to_kill*target_value - avg_losses;
|
||||
|
||||
//prefer to attack already damaged targets
|
||||
|
|
|
@ -171,7 +171,7 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
|
|||
//if this isn't the last scenario, then save the game
|
||||
if(scenario != NULL) {
|
||||
state.label = translate_string_default((*scenario)["id"],(*scenario)["name"]);
|
||||
state.starting_pos = *scenario;
|
||||
state.starting_pos = config();
|
||||
|
||||
bool retry = true;
|
||||
|
||||
|
@ -192,6 +192,8 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.starting_pos = *scenario;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -279,13 +279,17 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
else if(cmd == "allow_recruit") {
|
||||
const int side = maximum<int>(1,atoi(cfg["side"].c_str()));
|
||||
const size_t index = side-1;
|
||||
if(index > teams->size())
|
||||
if(index >= teams->size())
|
||||
return rval;
|
||||
|
||||
const std::string& type = cfg["type"];
|
||||
(*teams)[index].recruits().insert(type);
|
||||
if(index == 0) {
|
||||
state_of_game->can_recruit.insert(type);
|
||||
|
||||
const std::vector<std::string>& types = config::split(type);
|
||||
for(std::vector<std::string>::const_iterator i = types.begin(); i != types.end(); ++i) {
|
||||
(*teams)[index].recruits().insert(*i);
|
||||
if(index == 0) {
|
||||
state_of_game->can_recruit.insert(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,20 +297,23 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
else if(cmd == "disallow_recruit") {
|
||||
const int side = maximum<int>(1,atoi(cfg["side"].c_str()));
|
||||
const size_t index = side-1;
|
||||
if(index > teams->size())
|
||||
if(index >= teams->size())
|
||||
return rval;
|
||||
|
||||
const std::string& type = cfg["type"];
|
||||
(*teams)[index].recruits().erase(type);
|
||||
if(index == 0) {
|
||||
state_of_game->can_recruit.erase(type);
|
||||
const std::vector<std::string>& types = config::split(type);
|
||||
for(std::vector<std::string>::const_iterator i = types.begin(); i != types.end(); ++i) {
|
||||
(*teams)[index].recruits().erase(*i);
|
||||
if(index == 0) {
|
||||
state_of_game->can_recruit.erase(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if(cmd == "set_recruit") {
|
||||
const int side = maximum<int>(1,atoi(cfg["side"].c_str()));
|
||||
const size_t index = side-1;
|
||||
if(index > teams->size())
|
||||
if(index >= teams->size())
|
||||
return rval;
|
||||
|
||||
std::vector<std::string> recruit = config::split(cfg["recruit"]);
|
||||
|
@ -693,7 +700,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
std::vector<unit>& avail = state_of_game->available_units;
|
||||
for(std::vector<unit>::iterator u = avail.begin(); u != avail.end(); ++u) {
|
||||
if(u->matches_filter(cfg)) {
|
||||
gamemap::location loc;
|
||||
gamemap::location loc(cfg);
|
||||
recruit_unit(*game_map,1,*units,*u,loc,screen,false,true);
|
||||
avail.erase(u);
|
||||
break;
|
||||
|
|
|
@ -603,6 +603,7 @@ redo_turn:
|
|||
if((end_level.result == DEFEAT || end_level.result == VICTORY) && is_observer(teams)) {
|
||||
gui::show_dialog(gui,NULL,string_table["observer_endgame_heading"],
|
||||
string_table["observer_endgame"], gui::OK_ONLY);
|
||||
return end_level.result;
|
||||
}
|
||||
|
||||
if(end_level.result == QUIT || end_level.result == REPLAY) {
|
||||
|
|
|
@ -119,8 +119,7 @@ team::team_info::team_info(const config& cfg)
|
|||
}
|
||||
|
||||
std::vector<std::string> recruits = config::split(cfg["recruit"]);
|
||||
for(std::vector<std::string>::const_iterator i = recruits.begin();
|
||||
i != recruits.end(); ++i) {
|
||||
for(std::vector<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i) {
|
||||
can_recruit.insert(*i);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue