Speed up by keeping unit pointers in map, not units:
...makes AI sims much faster (class unit are now far too large to copy cheaply). 2p Blitz 800 gold turn 7 used to test: Before: 20 seconds to first AI move, 3:40 for AI turn. After: 7 seconds to first move, 1:02 for entire AI turn. (note: most of the remainder is animation time). To avoid everyone having to deal with pointers, new unit_map class works exactly like the old std::map unless you are adding/deleting/moving units. dfool: I removed a couple of redundant clear() calls in your AI, too.
This commit is contained in:
parent
b6a9d353b2
commit
4197721363
17 changed files with 346 additions and 116 deletions
|
@ -108,9 +108,10 @@ wesnoth_SOURCES = \
|
|||
tooltips.cpp \
|
||||
unit.cpp \
|
||||
unit_abilities.cpp \
|
||||
unit_display.cpp \
|
||||
unit_types.cpp \
|
||||
unit_animation.cpp \
|
||||
unit_display.cpp \
|
||||
unit_map.cpp \
|
||||
unit_types.cpp \
|
||||
upload_log.cpp \
|
||||
variable.cpp \
|
||||
video.cpp \
|
||||
|
@ -401,6 +402,7 @@ noinst_HEADERS = \
|
|||
intro.hpp \
|
||||
preferences.hpp \
|
||||
unit_types.hpp \
|
||||
unit_map.hpp \
|
||||
unit_animation.hpp \
|
||||
unit_abilities.hpp \
|
||||
unit_frame.hpp \
|
||||
|
|
|
@ -151,7 +151,7 @@ std::string recruit_unit(const gamemap& map, int side,
|
|||
disp->draw(true,true);
|
||||
}
|
||||
|
||||
units.insert(std::pair<gamemap::location,unit>( recruit_location,new_unit));
|
||||
units.add(new std::pair<gamemap::location,unit>(recruit_location,new_unit));
|
||||
|
||||
if(show) {
|
||||
unit_map::iterator un = disp->get_units().find(recruit_location);
|
||||
|
@ -894,7 +894,7 @@ void attack(display& gui, const gamemap& map,
|
|||
newunit.heal_all();
|
||||
}
|
||||
|
||||
units.insert(std::pair<gamemap::location,unit>(loc,newunit));
|
||||
units.replace(new std::pair<gamemap::location,unit>(loc,newunit));
|
||||
if (update_display){
|
||||
gui.invalidate(loc);
|
||||
}
|
||||
|
@ -1125,7 +1125,7 @@ void attack(display& gui, const gamemap& map,
|
|||
newunit.add_modification("variation",mod);
|
||||
}
|
||||
|
||||
units.insert(std::pair<gamemap::location,unit>(loc,newunit));
|
||||
units.replace(new std::pair<gamemap::location,unit>(loc,newunit));
|
||||
if (update_display){
|
||||
gui.invalidate(loc);
|
||||
}
|
||||
|
@ -1514,8 +1514,7 @@ void advance_unit(const game_data& info,
|
|||
preferences::encountered_units().insert(new_unit.id());
|
||||
LOG_STREAM(info, config) << "Added '" << new_unit.id() << "' to encountered units\n";
|
||||
|
||||
units.erase(loc);
|
||||
units.insert(std::pair<gamemap::location,unit>(loc,new_unit));
|
||||
units.replace(new std::pair<gamemap::location,unit>(loc,new_unit));
|
||||
LOG_NG << "firing post_advance event\n";
|
||||
game_events::fire("post_advance",loc);
|
||||
}
|
||||
|
@ -1679,8 +1678,7 @@ bool clear_shroud_unit(const gamemap& map,
|
|||
return false;
|
||||
}
|
||||
|
||||
unit_map temp_units;
|
||||
temp_units.insert(*u);
|
||||
unit_map temp_units(u->first, u->second);
|
||||
|
||||
paths p(map,status,gamedata,temp_units,loc,teams,true,false,teams[team]);
|
||||
for(paths::routes_map::const_iterator i = p.routes.begin();
|
||||
|
@ -1903,9 +1901,10 @@ size_t move_unit(display* disp, const game_data& gamedata,
|
|||
|
||||
u.set_movement(moves_left);
|
||||
|
||||
|
||||
units.erase(ui);
|
||||
ui = units.insert(std::pair<gamemap::location,unit>(steps.back(),u)).first;
|
||||
std::pair<gamemap::location,unit> *p = units.extract(ui->first);
|
||||
p->first = steps.back();
|
||||
units.add(p);
|
||||
ui = units.find(p->first);
|
||||
if(disp != NULL) {
|
||||
disp->invalidate_unit();
|
||||
disp->invalidate(steps.back());
|
||||
|
|
31
src/ai.cpp
31
src/ai.cpp
|
@ -414,8 +414,7 @@ gamemap::location ai_interface::move_unit_partial(location from, location to, st
|
|||
paths current_paths(info_.map,info_.state,info_.gameinfo,info_.units,from,info_.teams,ignore_zocs,teleport,current_team());
|
||||
|
||||
const std::map<location,paths>::iterator p_it = possible_moves.find(from);
|
||||
|
||||
unit current_unit = u_it->second;
|
||||
std::pair<gamemap::location,unit> *up = NULL;
|
||||
|
||||
if(p_it != possible_moves.end()) {
|
||||
paths& p = p_it->second;
|
||||
|
@ -427,7 +426,7 @@ gamemap::location ai_interface::move_unit_partial(location from, location to, st
|
|||
}
|
||||
|
||||
if(rt != p.routes.end()) {
|
||||
current_unit.set_movement(rt->second.move_left);
|
||||
u_it->second.set_movement(rt->second.move_left);
|
||||
|
||||
std::vector<location> steps = rt->second.steps;
|
||||
|
||||
|
@ -457,7 +456,7 @@ gamemap::location ai_interface::move_unit_partial(location from, location to, st
|
|||
}
|
||||
|
||||
if(n != 6) {
|
||||
current_unit.set_movement(0); //enter enemy ZoC, no movement left
|
||||
u_it->second.set_movement(0); //enter enemy ZoC, no movement left
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -469,20 +468,18 @@ gamemap::location ai_interface::move_unit_partial(location from, location to, st
|
|||
|
||||
info_.disp.scroll_to_tiles(from.x,from.y,to.x,to.y);
|
||||
|
||||
u_it->second.set_hidden(true);
|
||||
unit_display::move_unit(info_.disp,info_.map,steps,current_unit,info_.units,info_.teams);
|
||||
u_it->second.set_hidden(false);
|
||||
info_.units.erase(u_it);
|
||||
u_it = info_.units.end();
|
||||
up = info_.units.extract(u_it->first);
|
||||
unit_display::move_unit(info_.disp,info_.map,steps,up->second,info_.units,info_.teams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(u_it != info_.units.end()) {
|
||||
info_.units.erase(u_it);
|
||||
if (!up) {
|
||||
up = info_.units.extract(u_it->first);
|
||||
}
|
||||
|
||||
info_.units.insert(std::pair<location,unit>(to,current_unit));
|
||||
up->first = to;
|
||||
info_.units.add(up);
|
||||
if(info_.map.is_village(to)) {
|
||||
// if a new village is captured, disallow any future movement
|
||||
if (!info_.teams[info_.team_num-1].owns_village(to))
|
||||
|
@ -1852,8 +1849,7 @@ void ai::move_leader_after_recruit(const move_map& srcdst, const move_map& dstsr
|
|||
if(current_loc.valid()) {
|
||||
LOG_AI << "considering movement to " << str_cast(current_loc.x + 1)
|
||||
<< "," << str_cast(current_loc.y+1);
|
||||
unit_map temp_units;
|
||||
temp_units.insert(std::pair<location,unit>(current_loc,leader->second));
|
||||
unit_map temp_units(current_loc,leader->second);
|
||||
const paths p(map_,state_,gameinfo_,temp_units,current_loc,teams_,false,false,current_team());
|
||||
|
||||
if(p.routes.count(i->first)) {
|
||||
|
@ -1869,8 +1865,9 @@ void ai::move_leader_after_recruit(const move_map& srcdst, const move_map& dstsr
|
|||
//can recruit if they want.
|
||||
if(nearest_keep(leader->first) == leader->first) {
|
||||
const location keep = leader->first;
|
||||
const std::pair<location,unit> temp_leader = *leader;
|
||||
units_.erase(leader);
|
||||
std::pair<gamemap::location,unit> *temp_leader;
|
||||
|
||||
temp_leader = units_.extract(keep);
|
||||
|
||||
bool friend_can_reach_keep = false;
|
||||
|
||||
|
@ -1887,7 +1884,7 @@ void ai::move_leader_after_recruit(const move_map& srcdst, const move_map& dstsr
|
|||
}
|
||||
}
|
||||
|
||||
units_.insert(temp_leader);
|
||||
units_.add(temp_leader);
|
||||
|
||||
if(friend_can_reach_keep) {
|
||||
//find a location for our leader to vacate the keep to
|
||||
|
|
|
@ -340,12 +340,11 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units,
|
|||
std::vector<std::pair<location,location> >::const_iterator m;
|
||||
for (m = movements.begin(); m != movements.end(); ++m) {
|
||||
// We fix up units map to reflect what this would look like.
|
||||
unit_map::iterator att_it = units.find(m->first);
|
||||
unit att_u = att_it->second;
|
||||
units.erase(att_it);
|
||||
units.insert(std::pair<location,unit>(m->second, att_u));
|
||||
std::pair<gamemap::location,unit> *up = units.extract(m->first);
|
||||
up->first = m->second;
|
||||
units.add(up);
|
||||
|
||||
if (att_u.can_recruit()) {
|
||||
if (up->second.can_recruit()) {
|
||||
uses_leader = true;
|
||||
leader_threat = false;
|
||||
}
|
||||
|
@ -368,10 +367,10 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units,
|
|||
double prob_died = att.hp_dist[0];
|
||||
double prob_survived = (1.0 - prob_died) * prob_fought;
|
||||
|
||||
double cost = att_u.cost();
|
||||
double cost = up->second.cost();
|
||||
const bool on_village = map.is_village(m->second);
|
||||
//up to double the value of a unit based on experience
|
||||
cost += (double(att_u.experience())/double(att_u.max_experience()))*cost;
|
||||
cost += (double(up->second.experience())/double(up->second.max_experience()))*cost;
|
||||
resources_used += cost;
|
||||
avg_losses += cost * prob_died;
|
||||
|
||||
|
@ -384,8 +383,8 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units,
|
|||
|
||||
double advance_prob = 0.0;
|
||||
//the reward for advancing a unit is to get a 'negative' loss of that unit
|
||||
if (!att_u.advances_to().empty()) {
|
||||
int xp_for_advance = att_u.max_experience() - att_u.experience();
|
||||
if (!up->second.advances_to().empty()) {
|
||||
int xp_for_advance = up->second.max_experience() - up->second.experience();
|
||||
int kill_xp, fight_xp;
|
||||
|
||||
fight_xp = defend_it->second.level();
|
||||
|
@ -395,29 +394,29 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units,
|
|||
advance_prob = prob_fought;
|
||||
else if (kill_xp >= xp_for_advance)
|
||||
advance_prob = prob_killed;
|
||||
avg_losses -= att_u.cost() * advance_prob;
|
||||
avg_losses -= up->second.cost() * advance_prob;
|
||||
|
||||
//the reward for getting a unit closer to advancement (if
|
||||
//it didn't advance) is to get the proportion of remaining
|
||||
//experience needed, and multiply it by a quarter of the
|
||||
//unit cost. This will cause the AI to heavily favor
|
||||
//getting xp for close-to-advance units.
|
||||
avg_losses -= (att_u.cost()*fight_xp)/(xp_for_advance*4) * (prob_fought - prob_killed);
|
||||
avg_losses -= (att_u.cost()*kill_xp)/(xp_for_advance*4) * prob_killed;
|
||||
avg_losses -= (up->second.cost()*fight_xp)/(xp_for_advance*4) * (prob_fought - prob_killed);
|
||||
avg_losses -= (up->second.cost()*kill_xp)/(xp_for_advance*4) * prob_killed;
|
||||
|
||||
//the reward for killing with a unit that
|
||||
//plagues is to get a 'negative' loss of that unit
|
||||
if (bc.get_attacker_stats().plagues) {
|
||||
avg_losses -= prob_killed * att_u.cost();
|
||||
avg_losses -= prob_killed * up->second.cost();
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't advance, we took this damage.
|
||||
avg_damage_taken += (att_u.hitpoints() - att.average_hp()) * (1.0 - advance_prob);
|
||||
avg_damage_taken += (up->second.hitpoints() - att.average_hp()) * (1.0 - advance_prob);
|
||||
|
||||
// FIXME: attack_prediction.cpp should understand advancement directly.
|
||||
// For each level of attacker def gets 1 xp or kill_experience.
|
||||
def_avg_experience += att_u.level() *
|
||||
def_avg_experience += up->second.level() *
|
||||
(1.0 - att.hp_dist[0] + game_config::kill_experience * att.hp_dist[0]);
|
||||
if (m == movements.begin()) {
|
||||
first_chance_kill = def.hp_dist[0];
|
||||
|
@ -440,10 +439,9 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units,
|
|||
|
||||
// Restore the units to their original positions.
|
||||
for (m = movements.begin(); m != movements.end(); ++m) {
|
||||
unit_map::iterator att_it = units.find(m->second);
|
||||
unit att_u = att_it->second;
|
||||
units.erase(att_it);
|
||||
units.insert(std::pair<location,unit>(m->first, att_u));
|
||||
std::pair<gamemap::location,unit> *up = units.extract(m->second);
|
||||
up->first = m->first;
|
||||
units.add(up);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,6 @@ namespace dfool {
|
|||
unit_map matching_units;
|
||||
unit_map assigned_units;
|
||||
|
||||
assigned_units.clear();
|
||||
//find units assigned to this order;
|
||||
for(config::child_list::const_iterator at = order_assignments.begin(); at != order_assignments.end(); ++at) {
|
||||
LOG_STREAM(info, ai)<<"\tchecking for assignments\n";
|
||||
|
@ -110,7 +109,7 @@ namespace dfool {
|
|||
if(clear_assignment(i->first,clear_assign,info_.map)){
|
||||
LOG_STREAM(info, ai)<<"\tclear existing assignments\n";
|
||||
}else{
|
||||
assigned_units.insert(*i);
|
||||
assigned_units.add(new std::pair<gamemap::location,unit>(*i));
|
||||
LOG_STREAM(info, ai)<<"\t\tAssignment: "<<(**at)["unit_id"]<<" to order: "<<id<<std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +117,6 @@ namespace dfool {
|
|||
}
|
||||
}
|
||||
|
||||
matching_units.clear();
|
||||
//find units that match any filter. If no filters then accept all units.
|
||||
if(filter.size()){
|
||||
for(config::child_list::const_iterator f = filter.begin(); f != filter.end(); ++f) {
|
||||
|
@ -137,7 +135,7 @@ namespace dfool {
|
|||
if(found){
|
||||
LOG_STREAM(info, ai)<<"\t\talready assigned: "<<i->second.underlying_description()<<std::endl;
|
||||
}else{
|
||||
matching_units.insert(*i);
|
||||
matching_units.add(new std::pair<gamemap::location,unit>(*i));
|
||||
LOG_STREAM(info, ai)<<"\t\tmatching: "<<i->second.underlying_description()<<" to order: "<<id<<std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +147,7 @@ namespace dfool {
|
|||
//should add sorting functionality here in future
|
||||
//bring assigned units up to maximum number
|
||||
for(unit_map::const_iterator mu = matching_units.begin(); mu != matching_units.end() && order_assignments.size()<num; ++mu) {
|
||||
assigned_units.insert(*mu);
|
||||
assigned_units.add(new std::pair<gamemap::location,unit>(*mu));
|
||||
LOG_STREAM(info, ai)<<"\tassigned unit:\t"<<mu->second.underlying_description()<<"\n";
|
||||
}
|
||||
|
||||
|
@ -211,7 +209,7 @@ namespace dfool {
|
|||
}else{
|
||||
for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
|
||||
if(current_team().fogged(i->first.x,i->first.y) == false) {
|
||||
visible_units_.insert(*i);
|
||||
visible_units_.add(new std::pair<gamemap::location,unit>(*i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +224,7 @@ namespace dfool {
|
|||
unit_map filtered_units_;
|
||||
for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
|
||||
if(i->second.matches_filter(filter,i->first)) {
|
||||
filtered_units_.insert(*i);
|
||||
filtered_units_.add(new std::pair<gamemap::location,unit>(*i));
|
||||
}
|
||||
}
|
||||
return filtered_units_;
|
||||
|
|
|
@ -770,8 +770,7 @@ void ai::access_points(const move_map& srcdst, const location& u, const location
|
|||
return;
|
||||
}
|
||||
|
||||
unit_map single_unit;
|
||||
single_unit.insert(*u_it);
|
||||
unit_map single_unit(u_it->first, u_it->second);
|
||||
|
||||
const std::pair<move_map::const_iterator,move_map::const_iterator> locs = srcdst.equal_range(u);
|
||||
for(move_map::const_iterator i = locs.first; i != locs.second; ++i) {
|
||||
|
|
|
@ -122,8 +122,7 @@ void get_player_info(const config& cfg, game_state& gamestate, std::string save_
|
|||
}
|
||||
|
||||
new_unit.new_turn();
|
||||
units.insert(std::pair<gamemap::location,unit>(
|
||||
map.starting_position(new_unit.side()), new_unit));
|
||||
units.add(new std::pair<gamemap::location,unit>(map.starting_position(new_unit.side()), new_unit));
|
||||
LOG_NG << "initializing side '" << cfg["side"] << "' at "
|
||||
<< start_pos << '\n';
|
||||
}
|
||||
|
@ -168,7 +167,7 @@ void get_player_info(const config& cfg, game_state& gamestate, std::string save_
|
|||
") for a unit on side " +
|
||||
lexical_cast<std::string>(side) + ".");
|
||||
} else {
|
||||
units.insert(std::pair<gamemap::location,unit>(loc,new_unit));
|
||||
units.add(new std::pair<gamemap::location,unit>(loc,new_unit));
|
||||
LOG_NG << "inserting unit for side " << new_unit.side() << "\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -329,10 +329,9 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
if(game_map->on_board(vacant_dst)) {
|
||||
const int side = u->second.side();
|
||||
|
||||
//note that inserting into a map does not invalidate iterators
|
||||
//into the map, so this sequence is fine.
|
||||
units->insert(std::pair<gamemap::location,unit>(vacant_dst,u->second));
|
||||
units->erase(u);
|
||||
std::pair<gamemap::location,unit> *up = units->extract(u->first);
|
||||
up->first = dst;
|
||||
units->add(up);
|
||||
|
||||
if(game_map->is_village(vacant_dst)) {
|
||||
get_village(vacant_dst,*teams,side,*units);
|
||||
|
@ -1110,7 +1109,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
screen->draw(true,true);
|
||||
}
|
||||
|
||||
units->insert(std::pair<gamemap::location,unit>(loc,new_unit));
|
||||
units->add(new std::pair<gamemap::location,unit>(loc,new_unit));
|
||||
if(game_map->is_village(loc)) {
|
||||
get_village(loc,*teams,new_unit.side()-1,*units);
|
||||
}
|
||||
|
@ -1557,7 +1556,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
|
|||
}
|
||||
|
||||
units->erase(loc);
|
||||
units->insert(std::pair<gamemap::location,unit>(loc,u));
|
||||
units->add(new std::pair<gamemap::location,unit>(loc,u));
|
||||
|
||||
std::string text = cfg["text"];
|
||||
text = utils::interpolate_variables_into_string(text, *state_of_game);
|
||||
|
|
|
@ -18,6 +18,7 @@ class config;
|
|||
class gamestatus;
|
||||
class unit;
|
||||
class vconfig;
|
||||
class unit_map;
|
||||
|
||||
#include "terrain.hpp"
|
||||
|
||||
|
@ -104,7 +105,6 @@ public:
|
|||
private:
|
||||
void init(const std::string &x, const std::string &y);
|
||||
};
|
||||
typedef std::map<location,unit> unit_map;
|
||||
|
||||
const std::string& underlying_mvt_terrain(const location& loc) const
|
||||
{ return underlying_mvt_terrain(get_terrain(loc)); }
|
||||
|
|
|
@ -829,16 +829,12 @@ namespace events{
|
|||
|
||||
action.starting_moves = u->second.movement_left();
|
||||
|
||||
unit un = u->second;
|
||||
un.set_goto(gamemap::location());
|
||||
|
||||
u->second.set_hidden(true);
|
||||
unit_display::move_unit(*gui_,map_,route,un,units_,teams_);
|
||||
u->second.set_hidden(false);
|
||||
|
||||
units_.erase(u);
|
||||
un.set_movement(starting_moves);
|
||||
units_.insert(std::pair<gamemap::location,unit>(route.back(),un));
|
||||
std::pair<gamemap::location,unit> *up = units_.extract(u->first);
|
||||
unit_display::move_unit(*gui_,map_,route,up->second,units_,teams_);
|
||||
up->second.set_goto(gamemap::location());
|
||||
up->second.set_movement(starting_moves);
|
||||
up->first = route.back();
|
||||
units_.add(up);
|
||||
gui_->invalidate(route.back());
|
||||
gui_->draw();
|
||||
}
|
||||
|
@ -952,19 +948,15 @@ namespace events{
|
|||
|
||||
action.starting_moves = u->second.movement_left();
|
||||
|
||||
unit un = u->second;
|
||||
un.set_goto(gamemap::location());
|
||||
|
||||
u->second.set_hidden(true);
|
||||
unit_display::move_unit(*gui_,map_,route,un,units_,teams_);
|
||||
u->second.set_hidden(false);
|
||||
|
||||
units_.erase(u);
|
||||
un.set_movement(starting_moves);
|
||||
units_.insert(std::pair<gamemap::location,unit>(route.back(),un));
|
||||
std::pair<gamemap::location,unit> *up = units_.extract(u->first);
|
||||
unit_display::move_unit(*gui_,map_,route,up->second,units_,teams_);
|
||||
up->second.set_goto(gamemap::location());
|
||||
up->second.set_movement(starting_moves);
|
||||
up->first = route.back();
|
||||
units_.add(up);
|
||||
|
||||
if(map_.is_village(route.back())) {
|
||||
get_village(route.back(),teams_,un.side()-1,units_);
|
||||
get_village(route.back(),teams_,up->second.side()-1,units_);
|
||||
//MP_COUNTDOWN restore capture bonus
|
||||
if(action.countdown_time_bonus)
|
||||
{
|
||||
|
@ -1011,8 +1003,7 @@ namespace events{
|
|||
const unit_movement_resetter move_reset(u->second);
|
||||
const bool is_skirmisher = u->second.get_ability_bool("skirmisher",u->first);
|
||||
const bool teleports = u->second.get_ability_bool("teleport",u->first);
|
||||
unit_map units;
|
||||
units.insert(*u);
|
||||
unit_map units(u->first, u->second);
|
||||
const paths& path = paths(map_,status_,gameinfo_,ignore_units?units:units_,
|
||||
u->first,teams_,is_skirmisher,teleports,teams_[gui_->viewing_team()]);
|
||||
|
||||
|
@ -1162,7 +1153,7 @@ namespace events{
|
|||
|
||||
if (size_t(choice) < unit_choices.size()) {
|
||||
units_.erase(mousehandler.get_last_hex());
|
||||
units_.insert(std::pair<gamemap::location,unit>(mousehandler.get_last_hex(),unit_choices[choice]));
|
||||
units_.add(new std::pair<gamemap::location,unit>(mousehandler.get_last_hex(),unit_choices[choice]));
|
||||
gui_->invalidate(mousehandler.get_last_hex());
|
||||
gui_->invalidate_unit();
|
||||
}
|
||||
|
@ -1673,7 +1664,7 @@ namespace events{
|
|||
}
|
||||
|
||||
units_.erase(mousehandler.get_last_hex());
|
||||
units_.insert(std::pair<gamemap::location,unit>(mousehandler.get_last_hex(),unit(&gameinfo_,&units_,&map_,&status_,&teams_,&i->second,1,false)));
|
||||
units_.add(new std::pair<gamemap::location,unit>(mousehandler.get_last_hex(),unit(&gameinfo_,&units_,&map_,&status_,&teams_,&i->second,1,false)));
|
||||
gui_->invalidate(mousehandler.get_last_hex());
|
||||
gui_->invalidate_unit();
|
||||
} else if(game_config::debug && cmd == "gold") {
|
||||
|
|
|
@ -873,6 +873,7 @@ gamemap::location mouse_handler::current_unit_attacks_from(const gamemap::locati
|
|||
return res;
|
||||
}
|
||||
|
||||
// FIXME: Should borrow unit pointers, not copy units.
|
||||
const unit_map& mouse_handler::visible_units()
|
||||
{
|
||||
if(viewing_team().uses_shroud() == false && viewing_team().uses_fog() == false) {
|
||||
|
@ -883,7 +884,7 @@ const unit_map& mouse_handler::visible_units()
|
|||
visible_units_.clear();
|
||||
for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
|
||||
if((*gui_).fogged(i->first.x,i->first.y) == false) {
|
||||
visible_units_.insert(*i);
|
||||
visible_units_.add(new std::pair<gamemap::location,unit>(*i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -812,8 +812,6 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
|
||||
paths paths_list(map,state,gameinfo,units,src,teams,ignore_zocs,teleport,current_team);
|
||||
|
||||
unit current_unit = u->second;
|
||||
|
||||
std::map<gamemap::location,paths::route>::iterator rt = paths_list.routes.find(dst);
|
||||
if(rt == paths_list.routes.end()) {
|
||||
|
||||
|
@ -821,30 +819,31 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
ERR_NW << "can get to: " << rt->first << '\n';
|
||||
}
|
||||
|
||||
ERR_NW << "src cannot get to dst: " << current_unit.movement_left() << ' '
|
||||
ERR_NW << "src cannot get to dst: " << u->second.movement_left() << ' '
|
||||
<< paths_list.routes.size() << ' ' << src << " -> " << dst << '\n';
|
||||
if (!game_config::ignore_replay_errors) throw replay::error();
|
||||
}
|
||||
|
||||
rt->second.steps.push_back(dst);
|
||||
|
||||
if(!replayer.is_skipping() && unit_display::unit_visible_on_path(disp,rt->second.steps,current_unit,units,teams)) {
|
||||
if(!replayer.is_skipping() && unit_display::unit_visible_on_path(disp,rt->second.steps,u->second,units,teams)) {
|
||||
|
||||
disp.scroll_to_tiles(src.x,src.y,dst.x,dst.y);
|
||||
}
|
||||
|
||||
units.erase(u);
|
||||
std::pair<gamemap::location,unit> *up = units.extract(u->first);
|
||||
|
||||
if(!replayer.is_skipping()) {
|
||||
unit_display::move_unit(disp,map,rt->second.steps,current_unit,units,teams);
|
||||
unit_display::move_unit(disp,map,rt->second.steps,up->second,units,teams);
|
||||
}
|
||||
else{
|
||||
//unit location needs to be updated
|
||||
current_unit.set_goto(*(rt->second.steps.end() - 1));
|
||||
up->second.set_goto(*(rt->second.steps.end() - 1));
|
||||
}
|
||||
|
||||
current_unit.set_movement(rt->second.move_left);
|
||||
u = units.insert(std::pair<gamemap::location,unit>(dst,current_unit)).first;
|
||||
up->second.set_movement(rt->second.move_left);
|
||||
up->first = dst;
|
||||
units.add(up);
|
||||
if(map.is_village(dst)) {
|
||||
const int orig_owner = village_owner(dst,teams) + 1;
|
||||
if(orig_owner != team_num) {
|
||||
|
|
12
src/unit.cpp
12
src/unit.cpp
|
@ -2844,19 +2844,15 @@ std::string get_team_name(unsigned int side, const unit_map& units)
|
|||
}
|
||||
|
||||
temporary_unit_placer::temporary_unit_placer(unit_map& m, const gamemap::location& loc, const unit& u)
|
||||
: m_(m), loc_(loc), temp_(m.count(loc) == 1 ? m.find(loc)->second : u), use_temp_(m.count(loc) == 1)
|
||||
: m_(m), loc_(loc), temp_(m.extract(loc))
|
||||
{
|
||||
if(use_temp_) {
|
||||
m.erase(loc);
|
||||
}
|
||||
|
||||
m.insert(std::pair<gamemap::location,unit>(loc,u));
|
||||
m.add(new std::pair<gamemap::location,unit>(loc,u));
|
||||
}
|
||||
|
||||
temporary_unit_placer::~temporary_unit_placer()
|
||||
{
|
||||
m_.erase(loc_);
|
||||
if(use_temp_) {
|
||||
m_.insert(std::pair<gamemap::location,unit>(loc_,temp_));
|
||||
if(temp_) {
|
||||
m_.add(temp_);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,7 @@
|
|||
#include "team.hpp"
|
||||
#include "unit_types.hpp"
|
||||
#include "image.hpp"
|
||||
|
||||
|
||||
|
||||
#include "unit_map.hpp"
|
||||
|
||||
class unit;
|
||||
class display;
|
||||
|
@ -423,8 +421,7 @@ struct temporary_unit_placer
|
|||
private:
|
||||
unit_map& m_;
|
||||
const gamemap::location& loc_;
|
||||
const unit temp_;
|
||||
bool use_temp_;
|
||||
std::pair<gamemap::location,unit> *temp_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
104
src/unit_map.cpp
Normal file
104
src/unit_map.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2006 by Rusty Russell <rusty@rustcorp.com.au>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
#include "unit.hpp"
|
||||
#include "unit_map.hpp"
|
||||
#include "wassert.hpp"
|
||||
|
||||
// A unit map with a copy of a single unit in it.
|
||||
unit_map::unit_map(const gamemap::location &loc, const unit &u)
|
||||
{
|
||||
add(new std::pair<gamemap::location,unit>(loc, u));
|
||||
}
|
||||
|
||||
unit_map::unit_map(const unit_map &that)
|
||||
{
|
||||
*this = that;
|
||||
}
|
||||
|
||||
unit_map::unit_map &unit_map::operator =(const unit_map &that)
|
||||
{
|
||||
delete_all();
|
||||
for (pmap::const_iterator i = that.map_.begin(); i != that.map_.end(); i++) {
|
||||
add(new std::pair<gamemap::location,unit>(*i->second));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
unit_map::~unit_map()
|
||||
{
|
||||
delete_all();
|
||||
}
|
||||
|
||||
// Due to unit <-> unit_map dependencies, must be out of line.
|
||||
std::pair<gamemap::location,unit> unit_map::iterator::operator*() const
|
||||
{
|
||||
return *i_->second;
|
||||
}
|
||||
std::pair<gamemap::location,unit> unit_map::const_iterator::operator*() const
|
||||
{
|
||||
return *i_->second;
|
||||
}
|
||||
|
||||
void unit_map::add(std::pair<gamemap::location,unit> *p)
|
||||
{
|
||||
std::pair<pmap::iterator,bool> res = map_.insert(std::pair<gamemap::location,std::pair<gamemap::location,unit>*>(p->first, p));
|
||||
wassert(res.second);
|
||||
}
|
||||
|
||||
void unit_map::replace(std::pair<gamemap::location,unit> *p)
|
||||
{
|
||||
if (erase(p->first) != 1)
|
||||
assert(0);
|
||||
map_.insert(std::pair<gamemap::location,std::pair<gamemap::location,unit>*>(p->first, p));
|
||||
}
|
||||
|
||||
void unit_map::delete_all()
|
||||
{
|
||||
for (pmap::iterator i = map_.begin(); i != map_.end(); i++) {
|
||||
delete(i->second);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract (like erase, only don't delete).
|
||||
std::pair<gamemap::location,unit> *unit_map::extract(const gamemap::location &loc)
|
||||
{
|
||||
pmap::iterator i = map_.find(loc);
|
||||
if (i == map_.end())
|
||||
return NULL;
|
||||
std::pair<gamemap::location,unit> *res = i->second;
|
||||
map_.erase(i);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t unit_map::erase(const gamemap::location &loc)
|
||||
{
|
||||
pmap::iterator i = map_.find(loc);
|
||||
if (i == map_.end())
|
||||
return 0;
|
||||
|
||||
delete i->second;
|
||||
map_.erase(i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void unit_map::erase(iterator pos)
|
||||
{
|
||||
if (erase(pos->first) != 1)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void unit_map::clear()
|
||||
{
|
||||
delete_all();
|
||||
map_.clear();
|
||||
}
|
152
src/unit_map.hpp
Normal file
152
src/unit_map.hpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2006 by Rusty Russell <rusty@rustcorp.com.au>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
#ifndef UNIT_MAP_H_INCLUDED
|
||||
#define UNIT_MAP_H_INCLUDED
|
||||
|
||||
#include <cstring>
|
||||
#include "map.hpp"
|
||||
#include "unit.hpp"
|
||||
|
||||
// We used to just open-code a std::map<location,unit>, but as unit
|
||||
// gained weight leading up to 1.1.3, manipulating the map caused
|
||||
// significant performance issues for the AI, which had to actually
|
||||
// move units for accurate simulation with the new, more powerful
|
||||
// filtering. This class eases the transition, by providing a wrapper
|
||||
// which acts like a map of units, not unit pointers, except
|
||||
// implemented with pointers and hence providing a cheap a move
|
||||
// function.
|
||||
|
||||
class unit_map
|
||||
{
|
||||
public:
|
||||
unit_map() { };
|
||||
unit_map(const unit_map &that);
|
||||
unit_map &operator =(const unit_map &that);
|
||||
// A unit map with a single unit in it.
|
||||
explicit unit_map(const gamemap::location &loc, const unit &u);
|
||||
~unit_map();
|
||||
|
||||
// We actually keep map to pointers to pairs. Easy to fake iterators.
|
||||
typedef std::map<gamemap::location,std::pair<gamemap::location,unit>*> pmap;
|
||||
struct iterator;
|
||||
struct const_iterator {
|
||||
const_iterator() { }
|
||||
const_iterator(const iterator &i) : i_(i.i_) { }
|
||||
|
||||
const std::pair<gamemap::location,unit> *operator->() const
|
||||
{ return i_->second; }
|
||||
|
||||
std::pair<gamemap::location,unit> operator*() const;
|
||||
|
||||
const_iterator &operator++()
|
||||
{ ++i_; return *this; }
|
||||
|
||||
const_iterator &operator++(int)
|
||||
{ i_++; return *this; }
|
||||
|
||||
const_iterator &operator--()
|
||||
{ --i_; return *this; }
|
||||
|
||||
bool operator==(const const_iterator &that) const
|
||||
{ return that.i_ == this->i_; }
|
||||
|
||||
bool operator!=(const const_iterator &that) const
|
||||
{ return that.i_ != this->i_; }
|
||||
|
||||
explicit const_iterator(pmap::const_iterator i) : i_(i) { }
|
||||
|
||||
private:
|
||||
pmap::const_iterator i_;
|
||||
};
|
||||
|
||||
struct iterator {
|
||||
iterator() { }
|
||||
|
||||
std::pair<gamemap::location,unit> *operator->() const
|
||||
{ return i_->second; }
|
||||
|
||||
std::pair<gamemap::location,unit> operator*() const;
|
||||
|
||||
iterator &operator++()
|
||||
{ ++i_; return *this; }
|
||||
|
||||
iterator &operator++(int)
|
||||
{ i_++; return *this; }
|
||||
|
||||
bool operator==(const iterator &that) const
|
||||
{ return that.i_ == this->i_; }
|
||||
|
||||
bool operator!=(const iterator &that) const
|
||||
{ return that.i_ != this->i_; }
|
||||
|
||||
explicit iterator(pmap::iterator i) : i_(i) { }
|
||||
|
||||
friend struct const_iterator;
|
||||
private:
|
||||
pmap::iterator i_;
|
||||
};
|
||||
|
||||
iterator find(const gamemap::location &loc) {
|
||||
return iterator(map_.find(loc));
|
||||
}
|
||||
const_iterator find(const gamemap::location &loc) const {
|
||||
return const_iterator(map_.find(loc));
|
||||
}
|
||||
|
||||
size_t count(const gamemap::location &loc) const {
|
||||
return map_.count(loc);
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return iterator(map_.begin());
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return const_iterator(map_.begin());
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return iterator(map_.end());
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator(map_.end());
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return map_.size();
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
// Extract (like erase, only don't delete).
|
||||
std::pair<gamemap::location,unit> *extract(const gamemap::location &loc);
|
||||
|
||||
// Map owns pointer after this. Loc must be currently empty.
|
||||
void add(std::pair<gamemap::location,unit> *p);
|
||||
|
||||
// Like add, but loc must be occupied (implicitly erased).
|
||||
void replace(std::pair<gamemap::location,unit> *p);
|
||||
|
||||
void erase(iterator pos);
|
||||
size_t erase(const gamemap::location &loc);
|
||||
|
||||
private:
|
||||
|
||||
void delete_all();
|
||||
|
||||
// A map of pairs is redundant, but makes it possible to imitate a map of location,unit.
|
||||
std::map<gamemap::location,std::pair<gamemap::location,unit>*> map_;
|
||||
};
|
||||
|
||||
#endif // UNIT_MAP_H_INCLUDED
|
|
@ -30,7 +30,6 @@ class unit_ability_list;
|
|||
struct game_data;
|
||||
class gamestatus;
|
||||
class team;
|
||||
typedef std::map<gamemap::location,unit> unit_map;
|
||||
|
||||
//and how much damage it does.
|
||||
class attack_type
|
||||
|
|
Loading…
Add table
Reference in a new issue