added new ai parameters. Tweaked settings of Isle of Anduin scenario

This commit is contained in:
Dave White 2004-06-02 19:28:20 +00:00
parent 861a887613
commit 6105dc96f3
11 changed files with 198 additions and 73 deletions

View file

@ -5,19 +5,19 @@ sscccccssssssscccddccsccccssssss
sccddcccsssssccccgddcccccccccsss
ccdggdccscccscddcggddccdddcccsss
sccdtdccccccccdgcgggddddddddccss
sccdtdcccdddcdgtcggggddggdddccss
sccdgdcccdddcdgtcggggddggdddccss
sccdggdcdgggcdgccggtggggggddccss
ccdggggdggggcggcfgggggggfffddccs
ccdggttgggggcgccfggggggCCCfgddcc
ccdtgggggggtcgcffgggggtC1Cfgddcc
sccdggggggggcccfggggggfCCCffdccs
sccdggggtggggccftfggggftftffdccs
scccdgggggggggcfffggtfffffffddcc
sccdtgggggggggcfffggffffffffddcc
ccdgggggggggtgccmmmfffffffffgddc
ccdggggggggggmmcmmmffffffgggddcc
scctgtgggthhmmmccmmmfftfftggddcs
scddggggghhhmmccccmmggggggggdcss
ccdggggdgfggcggcggggggggfffddccs
ccdgggtggffgcgccgggggggCCCfgddcc
ccdtgggggggtcgcgggggggtC1Cfgddcc
sccdgffgggggcccgggggggfCCCffdccs
sccdggggtggggccgtgggggftftffdccs
scccdggggfggffcgggggtfffffffddcc
sccdtgfgggfgggcgggggffffffffddcc
ccdggggfggggtgccmmmfffffffffgddc
ccdgggfggggggmmcmmmffffffgggddcc
scctgggggthhmmmccmmmfftfftggddcs
scddgghhghhhmmccccmmggggggggdcss
ssdgggggghhhmmcccccmmhgggggfgdcs
sssddgggghhhmmcccccmmhgggggffdcs
sssssdtggghhhmmccccmmhggggggftdc

View file

@ -59,6 +59,24 @@ Defeat:
x=19
y=23
[/unit]
[ai]
village_value=0.0
leader_value=0.0
[target]
description=Konrad
value=8.0
[/target]
[protect_unit]
description=Konrad
radius=12
value=40.0
[/protect_unit]
[leader_goal]
x,y=1,1
[/leader_goal]
[/ai]
[/side]
#ifdef HARD

View file

@ -62,9 +62,19 @@ Defeat:
side=2
canrecruit=1
recruit=Orcish Grunt,Wolf Rider,Orcish Archer,Troll Whelp,Saurian
recruitment_pattern=scout,scout,fighter,fighter,archer
{GOLD 80 160 260}
{GOLD 40 120 180}
enemy=1
[ai]
recruitment_pattern=scout,scout,fighter,fighter,archer
[/ai]
#make the AI alot more aggressive at night
[ai]
time_of_day=dusk,first_watch,second_watch
aggression=0.75
caution=0
grouping=no
[/ai]
[/side]
#make the orcs start with a whole slew of villages

View file

@ -516,8 +516,9 @@ void ai::find_threats()
const protected_item& item = *k;
for(unit_map::const_iterator u = units_.begin(); u != units_.end(); ++u) {
if(current_team().is_enemy(u->second.side()) && distance_between(u->first,item.loc) < item.radius) {
add_target(target(u->first,item.value,target::THREAT));
const int distance = distance_between(u->first,item.loc);
if(current_team().is_enemy(u->second.side()) && distance < item.radius) {
add_target(target(u->first,item.value*double(item.radius-distance)/double(item.radius),target::THREAT));
}
}
}
@ -574,6 +575,8 @@ void ai::do_move()
}
}
move_leader_to_goals(enemy_dstsrc);
AI_DIAGNOSTIC("get villages phase");
std::cerr << "villages...\n";
@ -622,6 +625,7 @@ void ai::do_move()
//recruitment phase and leader movement phase
if(leader != units_.end()) {
if(!passive_leader) {
move_leader_to_keep(enemy_dstsrc);
}
@ -699,7 +703,7 @@ bool ai::do_combat(std::map<gamemap::location,paths>& possible_moves, const move
attack_enemy(to,target_loc,weapon);
//if this is the only unit in the planned attack, and the target
//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));
@ -708,20 +712,6 @@ bool ai::do_combat(std::map<gamemap::location,paths>& possible_moves, const move
return true;
} else {
log_scope("summoning reinforcements...\n");
std::set<gamemap::location> already_done;
for(std::vector<attack_analysis>::iterator it = analysis.begin(); it != analysis.end(); ++it) {
assert(it->movements.empty() == false);
const gamemap::location& loc = it->movements.front().first;
if(already_done.count(loc) > 0)
continue;
add_target(target(loc,3.0,target::BATTLE_AID));
already_done.insert(loc);
}
return false;
}
}
@ -1425,11 +1415,57 @@ void ai::do_recruitment()
}
}
void ai::move_leader_to_goals(const move_map& enemy_dstsrc)
{
const config* const goal = current_team().ai_parameters().child("leader_goal");
if(goal == NULL) {
AI_LOG("No goal found");
return;
}
const gamemap::location dst(*goal);
const unit_map::iterator leader = find_leader(units_,team_num_);
if(leader == units_.end() || leader->second.incapacitated()) {
AI_LOG("leader not found");
return;
}
AI_LOG("Doing recruitment before goals");
do_recruitment();
const paths::route route = a_star_search(leader->first,dst,1000.0,shortest_path_calculator(leader->second,current_team(),units_,teams_,map_,state_));
if(route.steps.empty()) {
AI_LOG("route empty");
return;
}
const paths leader_paths(map_,state_,gameinfo_,units_,leader->first,teams_,false,false);
std::map<gamemap::location,paths> possible_moves;
possible_moves.insert(std::pair<gamemap::location,paths>(leader->first,leader_paths));
gamemap::location loc;
for(std::vector<gamemap::location>::const_iterator itor = route.steps.begin(); itor != route.steps.end(); ++itor) {
if(leader_paths.routes.count(*itor) == 1) {
loc = *itor;
}
}
if(loc.valid()) {
AI_LOG("Moving leader to goal");
move_unit(leader->first,loc,possible_moves);
}
}
void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
{
const unit_map::iterator leader = find_leader(units_,team_num_);
if(leader == units_.end() || leader->second.stone())
if(leader == units_.end() || leader->second.incapacitated()) {
return;
}
//find where the leader can move
const paths leader_paths(map_,state_,gameinfo_,units_,leader->first,teams_,false,false);

View file

@ -340,6 +340,7 @@ protected:
virtual void move_leader_to_keep(const move_map& enemy_dstsrc);
virtual void move_leader_after_recruit(const move_map& enemy_dstsrc);
virtual void move_leader_to_goals(const move_map& enemy_dstsrc);
virtual bool recruit_usage(const std::string& usage);

View file

@ -523,7 +523,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
access_points(srcdst,best->first,best_target->loc,locs);
if(locs.empty() == false) {
AI_DIAGNOSTIC("supporting unit at " + str_cast(best_target->loc.x+1) + "," + str_cast(best_target->loc.y+1));
AI_LOG("supporting unit at " + str_cast(best_target->loc.x+1) + "," + str_cast(best_target->loc.y+1));
location best_loc;
int best_defense = 0;
double best_vulnerability = 0.0;
@ -578,14 +578,14 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
}
if(dangerous) {
AI_DIAGNOSTIC("dangerous path");
AI_LOG("dangerous path");
std::set<location> group, enemies;
const location dst = form_group(best_route.steps,dstsrc,srcdst,group);
enemies_along_path(best_route.steps,enemy_dstsrc,enemy_srcdst,enemies);
const double our_strength = compare_groups(group,enemies,best_route.steps);
if(our_strength > 1.0 + current_team().caution()) {
if(our_strength > 0.5 + current_team().caution()) {
AI_DIAGNOSTIC("moving group");
const bool res = move_group(dst,best_route.steps,group);
AI_DIAGNOSTIC("");
@ -599,7 +599,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
}
} else {
AI_DIAGNOSTIC("massing to attack " + str_cast(best_target->loc.x+1) + "," + str_cast(best_target->loc.y+1) + " " + str_cast(our_strength));
AI_LOG("massing to attack " + str_cast(best_target->loc.x+1) + "," + str_cast(best_target->loc.y+1) + " " + str_cast(our_strength));
const double value = best_target->value;
const location target_loc = best_target->loc;
@ -644,6 +644,9 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
}
}
AI_LOG("Best route is " + best->second.type().name() + " " + str_cast(best_route.steps.front().x+1) + "," + str_cast(best_route.steps.front().y+1) + " -> "
+ str_cast(best_route.steps.back().x+1) + "," + str_cast(best_route.steps.back().y+1));
for(std::vector<location>::reverse_iterator ri =
best_route.steps.rbegin(); ri != best_route.steps.rend(); ++ri) {
@ -673,9 +676,12 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
} else {
targets.erase(best_target);
}
AI_LOG("Moving to " + str_cast(its.first->first.x+1) + "," + str_cast(its.first->first.y+1));
return std::pair<location,location>(its.first->second,its.first->first);
} else {
AI_LOG("dangerous!");
is_dangerous = true;
}
}
@ -685,7 +691,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
}
if(best != units_.end()) {
std::cerr << "Could not make good move, staying still\n";
AI_LOG("Could not make good move, staying still");
//this sounds like the road ahead might be dangerous, and that's why we don't advance.
//create this as a target, attempting to rally units around
@ -693,7 +699,7 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
return std::pair<location,location>(best->first,best->first);
}
std::cerr << "Could not find anywhere to move!\n";
AI_LOG("Could not find anywhere to move!");
return std::pair<location,location>();
}

View file

@ -213,6 +213,7 @@ void read_game_cfg(preproc_map& defines, std::vector<line_source>& line_src, con
if(defines.size() < 4) {
bool is_valid = true;
std::stringstream str;
str << "-v" << game_config::version;
for(preproc_map::const_iterator i = defines.begin(); i != defines.end(); ++i) {
if(i->second.value != "" || i->second.arguments.empty() == false) {
is_valid = false;

View file

@ -1052,8 +1052,6 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
std::cerr << "placed castles\n";
std::cerr << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
if(nvillages > 0) {
const config* const naming = cfg.child("village_naming");
config naming_cfg;
@ -1070,16 +1068,20 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
//alternate between incrementing the x and y value. When they are high enough
//to equal or exceed the tiles_per_village, then we have them to the value
//we want them at.
size_t* village_ptr = &village_x;
while(village_x*village_y < tiles_per_village) {
(*village_ptr)++;
village_ptr = (village_ptr == &village_x ? &village_y : &village_x);
if(village_x < village_y) {
++village_x;
} else {
++village_y;
}
}
std::set<std::string> used_names;
for(size_t vx = 0; vx < width; vx += village_x) {
std::cerr << "village at " << vx << "\n";
for(size_t vy = rand()%village_y; vy < height; vy += village_y) {
const size_t add_x = rand()%3;
const size_t add_y = rand()%3;
const size_t x = (vx + add_x) - 1;

View file

@ -459,6 +459,8 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config,
calculate_healing(gui,status,map,units,player_number,teams);
}
team_it->set_time_of_day(status.get_time_of_day());
gui.set_playing_team(size_t(player_number-1));
clear_shroud(gui,status,map,gameinfo,units,teams,player_number-1);

View file

@ -12,6 +12,7 @@
*/
#include "game_config.hpp"
#include "gamestatus.hpp"
#include "network.hpp"
#include "replay.hpp"
#include "team.hpp"
@ -47,6 +48,31 @@ void team::target::write(config& cfg) const
team::team_info::team_info(const config& cfg)
{
//parse the ai parameters. AI parameters appear in [ai] tags. There may be multiple [ai] tags, which are
//appended onto each other. If an [ai] tag has a 'time_of_day' attribute, it is only active for that time
//of the day, and so we place it as part of a special map that gets calculated in team::new_turn
const config::child_list& ai_parameters = cfg.get_children("ai");
for(config::child_list::const_iterator aiparam = ai_parameters.begin(); aiparam != ai_parameters.end(); ++aiparam) {
const config& parm = **aiparam;
std::cerr << "parsing aiparam: '" << parm.write() << "'\n";
const std::string& tod = parm["time_of_day"];
if(tod == "") {
std::cerr << "appending to params\n";
ai_params.append(parm);
} else {
const std::vector<std::string>& tods = config::split(tod);
for(std::vector<std::string>::const_iterator i = tods.begin(); i != tods.end(); ++i) {
std::cerr << "appending to '" << *i << "'\n";
ai_params_tod[*i].append(parm);
}
}
}
for(string_map::const_iterator s = cfg.values.begin(); s != cfg.values.end(); ++s) {
ai_params[s->first] = s->second;
}
gold = cfg["gold"];
income = cfg["income"];
name = cfg["name"];
@ -62,18 +88,6 @@ team::team_info::team_info(const config& cfg)
else
income_per_village = atoi(village_income.c_str());
const std::string& aggression_val = cfg["aggression"];
if(aggression_val.empty())
aggression = 0.5;
else
aggression = atof(aggression_val.c_str());
const std::string& caution_val = cfg["caution"];
if(caution_val.empty())
caution = 0.25;
else
caution = atof(caution_val.c_str());
const std::string& enemies_list = cfg["enemy"];
if(!enemies_list.empty()) {
std::vector<std::string> venemies = config::split(enemies_list);
@ -94,27 +108,40 @@ team::team_info::team_info(const config& cfg)
ai_algorithm = cfg["ai_algorithm"];
const config::child_list& ai_parameters = cfg.get_children("ai");
for(config::child_list::const_iterator aiparam = ai_parameters.begin(); aiparam != ai_parameters.end(); ++aiparam) {
ai_params.append(**aiparam);
if(ai_algorithm.empty()) {
ai_algorithm = ai_params["ai_algorithm"];
}
std::string scouts_val = cfg["villages_per_scout"];
if(scouts_val.empty()) {
scouts_val = ai_params["villages_per_scout"];
}
const std::string& scouts_val = cfg["villages_per_scout"];
if(scouts_val.empty()) {
villages_per_scout = 4;
} else {
villages_per_scout = atoi(scouts_val.c_str());
}
const std::string& leader_val = cfg["leader_value"];
std::string leader_val = cfg["leader_value"];
if(leader_val.empty()) {
leader_val = ai_params["leader_value"];
}
if(leader_val.empty()) {
leader_value = 3.0;
} else {
leader_value = atof(leader_val.c_str());
}
const std::string& village_val = cfg["village_value"];
std::string village_val = cfg["village_value"];
if(village_val.empty()) {
village_val = ai_params["village_value"];
}
if(village_val.empty()) {
village_value = 1.0;
} else {
@ -126,7 +153,12 @@ team::team_info::team_info(const config& cfg)
can_recruit.insert(*i);
}
recruitment_pattern = config::split(cfg["recruitment_pattern"]);
std::string recruit_pattern = cfg["recruitment_pattern"];
if(recruit_pattern.empty()) {
recruit_pattern = ai_params["recruitment_pattern"];
}
recruitment_pattern = config::split(recruit_pattern);
//default recruitment pattern is to buy 2 fighters for every 1 archer
if(recruitment_pattern.empty()) {
@ -136,8 +168,12 @@ team::team_info::team_info(const config& cfg)
}
//additional targets
for(config::const_child_itors tgts = cfg.child_range("target");
tgts.first != tgts.second; ++tgts.first) {
config::const_child_itors tgts;
for(tgts = cfg.child_range("target"); tgts.first != tgts.second; ++tgts.first) {
targets.push_back(target(**tgts.first));
}
for(tgts = ai_params.child_range("target"); tgts.first != tgts.second; ++tgts.first) {
targets.push_back(target(**tgts.first));
}
@ -153,6 +189,11 @@ team::team_info::team_info(const config& cfg)
void team::team_info::write(config& cfg) const
{
cfg.add_child("ai",ai_params);
for(std::map<std::string,config>::const_iterator ai = ai_params_tod.begin(); ai != ai_params_tod.end(); ++ai) {
cfg.add_child("ai",ai->second)["time_of_day"] = ai->first;
}
cfg["gold"] = gold;
cfg["income"] = income;
cfg["name"] = name;
@ -163,9 +204,6 @@ void team::team_info::write(config& cfg) const
sprintf(buf,"%d",income_per_village);
cfg["village_gold"] = buf;
sprintf(buf,"%f",aggression);
cfg["aggression"] = buf;
std::stringstream enemies_str;
for(std::vector<int>::const_iterator en = enemies.begin(); en != enemies.end(); ++en) {
enemies_str << *en;
@ -304,6 +342,14 @@ void team::new_turn()
gold_ += income();
}
void team::set_time_of_day(const time_of_day& tod)
{
aiparams_ = info_.ai_params;
aiparams_.append(info_.ai_params_tod[tod.id]);
std::cerr << "for time of day '" << tod.id << "' set ai_params to: ---\n" << aiparams_.write() << "\n---\n";
}
void team::spend_gold(int amount)
{
gold_ -= amount;
@ -360,12 +406,12 @@ bool team::is_enemy(int n) const
double team::aggression() const
{
return info_.aggression;
return lexical_cast_default<double>(ai_parameters()["aggression"],0.5);
}
double team::caution() const
{
return info_.caution;
return lexical_cast_default<double>(ai_parameters()["caution"],0.25);
}
bool team::is_human() const
@ -415,7 +461,7 @@ const std::string& team::ai_algorithm() const
const config& team::ai_parameters() const
{
return info_.ai_params;
return aiparams_;
}
void team::make_network()

View file

@ -15,7 +15,6 @@
#include "config.hpp"
#include "map.hpp"
#include "unit.hpp"
#include <cassert>
#include <set>
@ -66,7 +65,6 @@ public:
int income_per_village;
std::set<std::string> can_recruit;
std::vector<std::string> recruitment_pattern;
double aggression, caution;
std::vector<int> enemies;
std::string team_name;
@ -77,6 +75,8 @@ public:
std::string ai_algorithm;
config ai_params;
std::map<std::string,config> ai_params_tod;
int villages_per_scout;
double leader_value, village_value;
@ -100,6 +100,7 @@ public:
int gold() const;
int income() const;
void new_turn();
void set_time_of_day(const struct time_of_day& tod);
void get_shared_maps();
void spend_gold(int amount);
void set_income(int amount);
@ -173,6 +174,8 @@ private:
bool auto_shroud_updates_;
team_info info_;
config aiparams_;
};
struct teams_manager {