changes to make AI smarter
This commit is contained in:
parent
7975077f57
commit
47c8c39a7b
10 changed files with 235 additions and 50 deletions
203
src/ai.cpp
203
src/ai.cpp
|
@ -158,6 +158,13 @@ void ai_interface::sync_network()
|
|||
network::send_data(cfg);
|
||||
|
||||
info_.start_command = info_.recorder.ncommands();
|
||||
|
||||
cfg.clear();
|
||||
while(network::connection res = network::receive_data(cfg)) {
|
||||
std::deque<config> backlog;
|
||||
info_.turn_data_.process_network_data(cfg,res,backlog);
|
||||
cfg.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,6 +272,76 @@ gamemap::location ai_interface::move_unit(location from, location to, std::map<l
|
|||
return to;
|
||||
}
|
||||
|
||||
gamemap::location ai::move_unit(location from, location to, std::map<location,paths>& possible_moves)
|
||||
{
|
||||
std::map<location,paths> temp_possible_moves;
|
||||
std::map<location,paths>* possible_moves_ptr = &possible_moves;
|
||||
|
||||
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.
|
||||
const gamemap::location& start_pos = map_.starting_position(i->second.side());
|
||||
if(i->first != start_pos && to != start_pos && units_.count(start_pos) == 0) {
|
||||
std::cerr << "when seeing if leader can move from " << (from.x+1) << "," << (from.y+1) << " -> " << (to.x+1) << "," << (to.y+1) << " seeing if can detour to keep at " << (start_pos.x+1) << "," << (start_pos.y+1) << "\n";
|
||||
const std::map<location,paths>::const_iterator moves = possible_moves.find(from);
|
||||
if(moves != possible_moves.end()) {
|
||||
|
||||
std::cerr << "found leader moves..\n";
|
||||
|
||||
bool can_make_it = false;
|
||||
int move_left = 0;
|
||||
|
||||
//see if the leader can make it to the keep, 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(start_pos);
|
||||
if(itor != moves->second.routes.end()) {
|
||||
move_left = itor->second.move_left;
|
||||
std::cerr << "can make it to keep with " << move_left << " movement left\n";
|
||||
unit temp_unit(i->second);
|
||||
temp_unit.set_movement(move_left);
|
||||
const temporary_unit_placer unit_placer(units_,start_pos,temp_unit);
|
||||
const paths leader_paths(map_,state_,gameinfo_,units_,start_pos,teams_,false,false);
|
||||
|
||||
std::cerr << "found " << leader_paths.routes.size() << " moves for temp leader\n";
|
||||
|
||||
//see if this leader could make it back to the keep
|
||||
if(leader_paths.routes.count(to) != 0) {
|
||||
std::cerr << "can make it back to the keep\n";
|
||||
can_make_it = true;
|
||||
}
|
||||
}
|
||||
|
||||
//if we can make it back to the keep and then to our original destination, do so.
|
||||
if(can_make_it) {
|
||||
from = ai_interface::move_unit(from,start_pos,possible_moves);
|
||||
if(from != start_pos) {
|
||||
return from;
|
||||
}
|
||||
|
||||
const unit_map::iterator itor = units_.find(from);
|
||||
if(itor != units_.end()) {
|
||||
itor->second.set_movement(move_left);
|
||||
}
|
||||
|
||||
move_map srcdst, dstsrc;
|
||||
calculate_possible_moves(temp_possible_moves,srcdst,dstsrc,false);
|
||||
possible_moves_ptr = &temp_possible_moves;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
do_recruitment();
|
||||
}
|
||||
|
||||
if(units_.count(to) == 0) {
|
||||
return ai_interface::move_unit(from,to,*possible_moves_ptr);
|
||||
} else {
|
||||
return from;
|
||||
}
|
||||
}
|
||||
|
||||
void ai_interface::calculate_possible_moves(std::map<location,paths>& res, move_map& srcdst, move_map& dstsrc, bool enemy, bool assume_full_movement)
|
||||
{
|
||||
for(std::map<gamemap::location,unit>::iterator un_it = info_.units.begin(); un_it != info_.units.end(); ++un_it) {
|
||||
|
@ -278,7 +355,7 @@ void ai_interface::calculate_possible_moves(std::map<location,paths>& res, move_
|
|||
}
|
||||
|
||||
//discount our own leader, and our units that have been turned to stone
|
||||
if(!enemy && un_it->second.can_recruit() || un_it->second.stone()) {
|
||||
if(/*!enemy && un_it->second.can_recruit() ||*/ un_it->second.stone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -397,6 +474,17 @@ void ai::do_move()
|
|||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool met_invisible_unit = move_to_targets(possible_moves,srcdst,dstsrc,enemy_srcdst,enemy_dstsrc,leader);
|
||||
if(met_invisible_unit) {
|
||||
do_move();
|
||||
|
@ -530,18 +618,66 @@ void ai_interface::attack_enemy(const location& u, const location& target, int w
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::pair<gamemap::location,gamemap::location> > ai::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,
|
||||
std::set<gamemap::location>& taken_villages, std::set<gamemap::location>& moved_units,
|
||||
const std::vector<std::pair<gamemap::location,gamemap::location> >& village_moves,
|
||||
std::vector<std::pair<gamemap::location,gamemap::location> >::const_iterator start_at)
|
||||
{
|
||||
const int leader_distance_from_keep = 10000;
|
||||
|
||||
std::vector<std::pair<location,location> > result;
|
||||
|
||||
for(std::vector<std::pair<location,location> >::const_iterator i = start_at; i != village_moves.end(); ++i) {
|
||||
if(taken_villages.count(i->first) || moved_units.count(i->second)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int distance = -1;
|
||||
|
||||
if(leader != units_.end() && leader->first == i->second) {
|
||||
const location& start_pos = map_.starting_position(leader->second.side());
|
||||
distance = distance_between(start_pos,i->first);
|
||||
}
|
||||
|
||||
taken_villages.insert(i->first);
|
||||
moved_units.insert(i->second);
|
||||
|
||||
std::vector<std::pair<location,location> > res = get_village_combinations(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
|
||||
const bool result_better = res.size() >= result.size() || res.size()+1 == result.size() && distance != -1 && distance < leader_distance_from_keep;
|
||||
if(result_better) {
|
||||
result.swap(res);
|
||||
result.push_back(*i);
|
||||
}
|
||||
|
||||
taken_villages.erase(i->first);
|
||||
moved_units.erase(i->second);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool ai::get_villages(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)
|
||||
{
|
||||
//try to acquire villages
|
||||
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
|
||||
if(map_.is_village(i->first) == false) {
|
||||
//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(); j != dstsrc.end() && village_moves.size() < max_village_moves; ++j) {
|
||||
if(map_.is_village(j->first) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool want_village = true, owned = false;
|
||||
for(size_t j = 0; j != teams_.size(); ++j) {
|
||||
owned = teams_[j].owns_village(i->first);
|
||||
if(owned && !current_team().is_enemy(j+1)) {
|
||||
for(size_t n = 0; n != teams_.size(); ++n) {
|
||||
owned = teams_[n].owns_village(j->first);
|
||||
if(owned && !current_team().is_enemy(n+1)) {
|
||||
want_village = false;
|
||||
}
|
||||
|
||||
|
@ -552,28 +688,27 @@ bool ai::get_villages(std::map<gamemap::location,paths>& possible_moves, const m
|
|||
|
||||
//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(!owned && leader == units_.end())
|
||||
if(!owned && leader == units_.end()) {
|
||||
want_village = false;
|
||||
}
|
||||
|
||||
if(want_village) {
|
||||
std::cerr << "trying to acquire village: " << i->first.x
|
||||
<< ", " << i->first.y << "\n";
|
||||
|
||||
const std::map<location,unit>::iterator un = units_.find(i->second);
|
||||
if(un == units_.end()) {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(un->second.is_guardian())
|
||||
continue;
|
||||
|
||||
move_unit(i->second,i->first,possible_moves);
|
||||
return true;
|
||||
village_moves.push_back(*j);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
std::set<location> taken_villages, moved_units;
|
||||
const int ticks = SDL_GetTicks();
|
||||
std::cerr << "get_villages()..." << village_moves.size() << "\n";
|
||||
const std::vector<std::pair<location,location> >& moves = get_village_combinations(possible_moves,srcdst,dstsrc,enemy_srcdst,enemy_dstsrc,leader,
|
||||
taken_villages,moved_units,village_moves,village_moves.begin());
|
||||
std::cerr << "get_villages() done: " << (SDL_GetTicks() - ticks) << "\n";
|
||||
|
||||
for(std::vector<std::pair<location,location> >::const_iterator i = moves.begin(); i != moves.end(); ++i) {
|
||||
move_unit(i->second,i->first,possible_moves);
|
||||
}
|
||||
|
||||
return moves.empty() == false;
|
||||
}
|
||||
|
||||
bool ai::get_healing(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)
|
||||
|
@ -1077,6 +1212,28 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
|
|||
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
|
||||
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.
|
||||
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) {
|
||||
const int new_distance = distance_between(i->first,start_pos);
|
||||
if(new_distance < current_distance) {
|
||||
moves_toward_keep.insert(std::pair<int,gamemap::location>(new_distance,i->first));
|
||||
}
|
||||
}
|
||||
|
||||
//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) {
|
||||
if(enemy_dstsrc.count(j->second) == 0) {
|
||||
move_unit(leader->first,j->second,possible_moves);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
12
src/ai.hpp
12
src/ai.hpp
|
@ -325,6 +325,18 @@ protected:
|
|||
|
||||
virtual bool recruit_usage(const std::string& usage);
|
||||
|
||||
//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,
|
||||
std::set<location>& taken_villages, std::set<location>& moved_units,
|
||||
const std::vector<std::pair<gamemap::location,gamemap::location> >& village_moves,
|
||||
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.
|
||||
location move_unit(location from, location to, std::map<location,paths>& possible_moves);
|
||||
|
||||
struct attack_analysis
|
||||
{
|
||||
void analyze(const gamemap& map, std::map<location,unit>& units,
|
||||
|
|
|
@ -112,8 +112,9 @@ void ai::do_attack_analysis(
|
|||
|
||||
//check to see whether this move would be a backstab
|
||||
int backstab_bonus = 1;
|
||||
double surround_bonus = 1.0;
|
||||
|
||||
if(backstab && tiles[(j+3)%6] != current_unit) {
|
||||
if(tiles[(j+3)%6] != current_unit) {
|
||||
const unit_map::const_iterator itor = units_.find(tiles[(j+3)%6]);
|
||||
|
||||
//note that we *could* also check if a unit plans to move there before we're
|
||||
|
@ -122,8 +123,14 @@ void ai::do_attack_analysis(
|
|||
//make our analysis look *worse* instead of better.
|
||||
//so we only check for 'concrete' backstab opportunities.
|
||||
if(itor != units_.end() && itor->second.side() == unit_itor->second.side()) {
|
||||
backstab_bonus = 2;
|
||||
if(backstab) {
|
||||
backstab_bonus = 2;
|
||||
}
|
||||
|
||||
surround_bonus = 1.2;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//see if this position is the best rated we've seen so far
|
||||
|
@ -142,14 +149,14 @@ void ai::do_attack_analysis(
|
|||
|
||||
//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 - support >= best_vulnerability - best_support) {
|
||||
if(cur_position >= 0 && rating == best_rating && vulnerability/surround_bonus - support*surround_bonus >= best_vulnerability - best_support) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cur_position = j;
|
||||
best_rating = rating;
|
||||
best_vulnerability = vulnerability;
|
||||
best_support = support;
|
||||
best_vulnerability = vulnerability/surround_bonus;
|
||||
best_support = support*surround_bonus;
|
||||
}
|
||||
|
||||
if(cur_position != -1) {
|
||||
|
@ -425,17 +432,17 @@ void ai::attack_analysis::analyze(const gamemap& map,
|
|||
|
||||
//if the attacker moved onto a village, reward it for doing so
|
||||
else if(on_village) {
|
||||
atthp += game_config::heal_amount*2; //double reward to emphasize getting onto villages
|
||||
atthp += game_config::cure_amount*2; //double reward to emphasize getting onto villages
|
||||
}
|
||||
|
||||
defenderxp += (atthp == 0 ? 8:1)*att->second.type().level();
|
||||
defenderxp += (atthp == 0 ? game_config::kill_experience:1)*att->second.type().level();
|
||||
|
||||
avg_damage_taken += hitpoints[i] - atthp;
|
||||
}
|
||||
|
||||
//penalty for allowing advancement is a 'negative' kill, and
|
||||
//defender's hitpoints get restored to maximum
|
||||
if(defend_it->second.experience() < defend_it->second.max_experience()&&
|
||||
if(defend_it->second.experience() < defend_it->second.max_experience() &&
|
||||
defend_it->second.experience() + defenderxp >=
|
||||
defend_it->second.max_experience()) {
|
||||
chance_to_kill -= 1.0;
|
||||
|
@ -443,7 +450,7 @@ void ai::attack_analysis::analyze(const gamemap& map,
|
|||
} else if(defhp == 0) {
|
||||
chance_to_kill += 1.0;
|
||||
} else if(map.is_village(defend_it->first)) {
|
||||
defhp += game_config::heal_amount;
|
||||
defhp += game_config::cure_amount;
|
||||
if(defhp > target_hp)
|
||||
defhp = target_hp;
|
||||
}
|
||||
|
|
|
@ -99,26 +99,30 @@ std::vector<ai::target> ai::find_targets(unit_map::const_iterator leader, const
|
|||
|
||||
std::vector<target> targets;
|
||||
|
||||
//if enemy units are in range of the leader, then we rally to the leader's defense
|
||||
//if enemy units are in range of the leader, then we target the enemies who are in range.
|
||||
if(has_leader) {
|
||||
const double threat = power_projection(leader->first,enemy_srcdst,enemy_dstsrc);
|
||||
if(threat > 0.0) {
|
||||
//find the specific tiles the enemy can reach, and set them as targets
|
||||
std::vector<gamemap::location> threatened_tiles;
|
||||
//find the location of enemy threats
|
||||
std::set<gamemap::location> threats;
|
||||
|
||||
gamemap::location adj[6];
|
||||
get_adjacent_tiles(leader->first,adj);
|
||||
for(size_t n = 0; n != 6; ++n) {
|
||||
if(enemy_dstsrc.count(adj[n]) > 0) {
|
||||
threatened_tiles.push_back(adj[n]);
|
||||
std::pair<move_map::const_iterator,move_map::const_iterator> itors = enemy_dstsrc.equal_range(adj[n]);
|
||||
while(itors.first != itors.second) {
|
||||
if(units_.count(itors.first->second)) {
|
||||
threats.insert(itors.first->second);
|
||||
}
|
||||
|
||||
++itors.first;
|
||||
}
|
||||
}
|
||||
|
||||
assert(threatened_tiles.size() > 0);
|
||||
assert(threats.empty() == false);
|
||||
|
||||
//divide the threat into the tiles the enemy can reach, and try to
|
||||
//get units to reach those tiles
|
||||
const double value = threat/double(threatened_tiles.size());
|
||||
for(std::vector<gamemap::location>::const_iterator i = threatened_tiles.begin(); i != threatened_tiles.end(); ++i) {
|
||||
const double value = threat/double(threats.size());
|
||||
for(std::set<gamemap::location>::const_iterator i = threats.begin(); i != threats.end(); ++i) {
|
||||
targets.push_back(target(*i,value));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ map_editor::~map_editor() {
|
|||
try {
|
||||
write_file(prefs_filename, prefs_.write());
|
||||
}
|
||||
catch (io_exception e) {
|
||||
catch (io_exception& e) {
|
||||
std::cerr << "Error when writing to " << prefs_filename << ": "
|
||||
<< e.what() << std::endl;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ void terrain_palette::adjust_size() {
|
|||
const unsigned terrains_fitting =
|
||||
(unsigned)(space_for_terrains / size_specs_.terrain_space) * 2;
|
||||
const unsigned total_terrains = num_terrains();
|
||||
nterrains_ = minimum(terrains_fitting, total_terrains);
|
||||
nterrains_ = minimum<int>(terrains_fitting, total_terrains);
|
||||
bot_button_y_ = size_specs_.palette_y + (nterrains_ / 2) * size_specs_.terrain_space +
|
||||
button_palette_padding * 2 + button_height;
|
||||
top_button_.set_location(button_x_, top_button_y_);
|
||||
|
|
|
@ -781,9 +781,7 @@ void floating_label::draw(SDL_Surface* screen)
|
|||
|
||||
SDL_Rect rect = {xpos(surf_->w),int(ypos_),surf_->w,surf_->h};
|
||||
const clip_rect_setter clip_setter(screen,clip_rect_);
|
||||
std::cerr << "blit a\n";
|
||||
SDL_BlitSurface(screen,&rect,buf_,NULL);
|
||||
std::cerr << "blit b\n";
|
||||
SDL_BlitSurface(surf_,NULL,screen,&rect);
|
||||
|
||||
if(foreground_ != NULL) {
|
||||
|
|
|
@ -619,7 +619,6 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
else if(cmd == "unit_overlay") {
|
||||
for(std::map<gamemap::location,unit>::iterator itor = units->begin(); itor != units->end(); ++itor) {
|
||||
if(game_events::unit_matches_filter(itor,cfg)) {
|
||||
std::cerr << "adding overlay '" << cfg["image"] << "' to '" << itor->second.description() << "'\n";
|
||||
itor->second.add_overlay(cfg["image"]);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
|
|||
turn_data.move_unit_to_loc(ui,ui->second.get_goto(),false);
|
||||
}
|
||||
|
||||
turn_data.start_interative_turn();
|
||||
turn_data.start_interactive_turn();
|
||||
|
||||
while(!turn_data.turn_over()) {
|
||||
|
||||
|
@ -122,6 +122,11 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
|
|||
|
||||
start_command = turn_data.send_data(start_command);
|
||||
}
|
||||
|
||||
//send one more time to make sure network is up-to-date.
|
||||
start_command = turn_data.send_data(start_command);
|
||||
|
||||
assert(start_command == recorder.ncommands());
|
||||
}
|
||||
|
||||
turn_info::turn_info(game_data& gameinfo, game_state& state_of_game,
|
||||
|
@ -184,6 +189,8 @@ int turn_info::send_data(int first_command)
|
|||
config cfg;
|
||||
const config& obj = cfg.add_child("turn",recorder.get_data_range(first_command,recorder.ncommands()));
|
||||
|
||||
std::cerr << "sending commands " << first_command << "-" << recorder.ncommands() << ": '"
|
||||
<< obj.write() << "'\n";
|
||||
if(obj.empty() == false) {
|
||||
network::send_data(cfg);
|
||||
}
|
||||
|
@ -888,7 +895,7 @@ void turn_info::move_unit_to_loc(const unit_map::const_iterator& ui, const gamem
|
|||
gui_.invalidate_game_status();
|
||||
}
|
||||
|
||||
void turn_info::start_interative_turn() {
|
||||
void turn_info::start_interactive_turn() {
|
||||
std::cerr << "done gotos\n";
|
||||
start_ncmd_ = recorder.ncommands();
|
||||
}
|
||||
|
@ -1873,6 +1880,7 @@ void turn_info::do_speak(const std::string& message, bool allies_only)
|
|||
cfg["team_name"] = teams_[gui_.viewing_team()].team_name();
|
||||
}
|
||||
|
||||
std::cerr << "logging speech: '" << cfg.write() << "'\n";
|
||||
recorder.speak(cfg);
|
||||
gui_.add_chat_message(cfg["description"],side,message,
|
||||
private_message ? display::MESSAGE_PRIVATE : display::MESSAGE_PUBLIC);
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
bool in_context_menu(hotkey::HOTKEY_COMMAND command) const;
|
||||
|
||||
void move_unit_to_loc(const unit_map::const_iterator& ui, const gamemap::location& target, bool continue_move);
|
||||
void start_interative_turn();
|
||||
void start_interactive_turn();
|
||||
|
||||
void save_game(const std::string& message,gui::DIALOG_TYPE dialog_type);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue