00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pathfind/teleport.hpp"
00016
00017 #include "serialization/string_utils.hpp"
00018 #include "unit.hpp"
00019 #include "log.hpp"
00020 #include "resources.hpp"
00021
00022 #include "foreach.hpp"
00023
00024 static lg::log_domain log_engine("engine");
00025 #define ERR_PF LOG_STREAM(err, log_engine)
00026
00027 namespace {
00028 const std::string reversed_suffix = "-__REVERSED__";
00029 }
00030
00031
00032 pathfind::teleport_group::teleport_group(const config& cfg) : cfg_(cfg), reversed_(cfg["reversed"].to_bool(false)), id_(cfg["id"])
00033 {
00034 assert(cfg.has_attribute("id"));
00035 assert(cfg.has_attribute("reversed"));
00036
00037 assert(cfg_.child_count("source") == 1);
00038 assert(cfg_.child_count("target") == 1);
00039 assert(cfg_.child_count("filter") == 1);
00040 }
00041
00042 pathfind::teleport_group::teleport_group(const vconfig& cfg, bool reversed) : cfg_(cfg.get_config()), reversed_(reversed), id_()
00043 {
00044 assert(cfg_.child_count("source") == 1);
00045 assert(cfg_.child_count("target") == 1);
00046 assert(cfg_.child_count("filter") == 1);
00047 if (cfg["id"].empty()) {
00048 id_ = resources::tunnels->next_unique_id();
00049 } else {
00050 id_ = cfg["id"].str();
00051 if (reversed_)
00052 id_ += reversed_suffix;
00053 }
00054 }
00055
00056 void pathfind::teleport_group::get_teleport_pair(
00057 teleport_pair& loc_pair
00058 , const unit& u
00059 , const bool ignore_units) const
00060 {
00061 const map_location &loc = u.get_location();
00062 static unit_map empty_unit_map;
00063 unit_map *units;
00064 if (ignore_units) {
00065 units = &empty_unit_map;
00066 } else {
00067 units = resources::units;
00068 }
00069 vconfig filter(cfg_.child_or_empty("filter"), true);
00070 vconfig source(cfg_.child_or_empty("source"), true);
00071 vconfig target(cfg_.child_or_empty("target"), true);
00072 if (u.matches_filter(filter, loc)) {
00073
00074 scoped_xy_unit teleport_unit("teleport_unit", loc.x, loc.y, *resources::units);
00075
00076 terrain_filter source_filter(source, *units);
00077 source_filter.get_locations(reversed_ ? loc_pair.second : loc_pair.first);
00078
00079 terrain_filter target_filter(target, *units);
00080 target_filter.get_locations(reversed_ ? loc_pair.first : loc_pair.second);
00081 }
00082 }
00083
00084 const std::string& pathfind::teleport_group::get_teleport_id() const {
00085 return id_;
00086 }
00087
00088 bool pathfind::teleport_group::always_visible() const {
00089 return cfg_["always_visible"].to_bool(false);
00090 }
00091
00092 config pathfind::teleport_group::to_config() const {
00093 config retval = cfg_;
00094 retval["saved"] = "yes";
00095 retval["reversed"] = reversed_ ? "yes" : "no";
00096 retval["id"] = id_;
00097 return retval;
00098 }
00099
00100 pathfind::teleport_map::teleport_map(
00101 const std::vector<teleport_group>& groups
00102 , const unit& u
00103 , const team &viewing_team
00104 , const bool see_all
00105 , const bool ignore_units)
00106 : teleport_map_()
00107 , sources_()
00108 , targets_()
00109 {
00110
00111 foreach(const teleport_group& group, groups) {
00112
00113 teleport_pair locations;
00114 group.get_teleport_pair(locations, u, ignore_units);
00115 if (!see_all && !group.always_visible() && viewing_team.is_enemy(u.side())) {
00116 teleport_pair filter_locs;
00117 foreach(const map_location &loc, locations.first)
00118 if(!viewing_team.fogged(loc))
00119 filter_locs.first.insert(loc);
00120 foreach(const map_location &loc, locations.second)
00121 if(!viewing_team.fogged(loc))
00122 filter_locs.second.insert(loc);
00123 locations.first.swap(filter_locs.first);
00124 locations.second.swap(filter_locs.second);
00125 }
00126 std::string teleport_id = group.get_teleport_id();
00127
00128 std::set<map_location>::iterator source_it = locations.first.begin();
00129 for (; source_it != locations.first.end(); ++source_it ) {
00130 if(teleport_map_.count(*source_it) == 0) {
00131 std::set<std::string> id_set;
00132 id_set.insert(teleport_id);
00133 teleport_map_.insert(std::make_pair(*source_it, id_set));
00134 } else {
00135 (teleport_map_.find(*source_it)->second).insert(teleport_id);
00136 }
00137 }
00138 sources_.insert(std::make_pair(teleport_id, locations.first));
00139 targets_.insert(std::make_pair(teleport_id, locations.second));
00140 }
00141 }
00142
00143 void pathfind::teleport_map::get_adjacents(std::set<map_location>& adjacents, map_location loc) const {
00144
00145 if (teleport_map_.count(loc) == 0) {
00146 return;
00147 } else {
00148 const std::set<std::string>& keyset = (teleport_map_.find(loc)->second);
00149 for(std::set<std::string>::const_iterator it = keyset.begin(); it != keyset.end(); ++it) {
00150
00151 const std::set<map_location>& target = targets_.find(*it)->second;
00152 adjacents.insert(target.begin(), target.end());
00153 }
00154 }
00155 }
00156
00157 void pathfind::teleport_map::get_sources(std::set<map_location>& sources) const {
00158
00159 std::map<std::string, std::set<map_location> >::const_iterator it;
00160 for(it = sources_.begin(); it != sources_.end(); ++it) {
00161 sources.insert(it->second.begin(), it->second.end());
00162 }
00163 }
00164
00165 void pathfind::teleport_map::get_targets(std::set<map_location>& targets) const {
00166
00167 std::map<std::string, std::set<map_location> >::const_iterator it;
00168 for(it = targets_.begin(); it != targets_.end(); ++it) {
00169 targets.insert(it->second.begin(), it->second.end());
00170 }
00171 }
00172
00173
00174 const pathfind::teleport_map pathfind::get_teleport_locations(const unit &u,
00175 const team &viewing_team,
00176 bool see_all, bool ignore_units)
00177 {
00178 std::vector<teleport_group> groups;
00179
00180 if (u.get_ability_bool("teleport")) {
00181
00182 unit_ability_list teleport_list = u.get_abilities("teleport");
00183
00184 std::vector<std::pair<const config *, map_location> > teleports = teleport_list.cfgs;
00185 std::vector<std::pair<const config *, map_location> >::const_iterator it = teleports.begin();
00186
00187 for(; it != teleports.end(); ++it) {
00188 const int tunnel_count = (it->first)->child_count("tunnel");
00189 for(int i = 0; i < tunnel_count; ++i) {
00190 config teleport_group_cfg = (it->first)->child("tunnel", i);
00191 teleport_group group = teleport_group(vconfig(teleport_group_cfg, true), false);
00192 groups.push_back(group);
00193 }
00194 }
00195 }
00196
00197 const std::vector<teleport_group>& global_groups = resources::tunnels->get();
00198 groups.insert(groups.end(), global_groups.begin(), global_groups.end());
00199
00200 return teleport_map(groups, u, viewing_team, see_all, ignore_units);
00201 }
00202
00203 pathfind::manager::manager(const config &cfg) : tunnels_(), id_(lexical_cast_default<int>(cfg["next_teleport_group_id"], 0)) {
00204 const int tunnel_count = cfg.child_count("tunnel");
00205 for(int i = 0; i < tunnel_count; ++i) {
00206 const config& t = cfg.child("tunnel", i);
00207 if(!t["saved"].to_bool()) {
00208 lg::wml_error << "Do not use [tunnel] directly in a [scenario]. Use it in an [event] or [abilities] tag.\n";
00209 continue;
00210 }
00211 const pathfind::teleport_group tunnel(t);
00212 this->add(tunnel);
00213 }
00214 }
00215
00216 void pathfind::manager::add(const teleport_group &group) {
00217 tunnels_.push_back(group);
00218 }
00219
00220 void pathfind::manager::remove(const std::string &id) {
00221 std::vector<pathfind::teleport_group>::iterator t = tunnels_.begin();
00222 for(;t != tunnels_.end();) {
00223 if (t->get_teleport_id() == id || t->get_teleport_id() == id + reversed_suffix) {
00224 t = tunnels_.erase(t);
00225 } else {
00226 ++t;
00227 }
00228 }
00229 }
00230
00231 const std::vector<pathfind::teleport_group>& pathfind::manager::get() const {
00232 return tunnels_;
00233 }
00234
00235 config pathfind::manager::to_config() const {
00236 config store;
00237
00238 std::vector<pathfind::teleport_group>::const_iterator tunnel = tunnels_.begin();
00239 for(; tunnel != tunnels_.end(); ++tunnel) {
00240 store.add_child("tunnel", tunnel->to_config());
00241 }
00242 store["next_teleport_group_id"] = str_cast(id_);
00243
00244 return store;
00245 }
00246
00247 std::string pathfind::manager::next_unique_id() {
00248 return str_cast(++id_);
00249 }
00250