The Battle for Wesnoth  1.15.0+dev
teleport.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2018 by Fabian Mueller <fabianmueller5@gmx.de>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License version 2
7  or at your option any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY.
10 
11  See the COPYING file for more details.
12 */
13 
14 #include "pathfind/teleport.hpp"
15 
16 #include "display_context.hpp"
17 #include "filter_context.hpp"
18 #include "game_board.hpp"
19 #include "log.hpp"
20 #include "resources.hpp"
22 #include "team.hpp"
23 #include "terrain/filter.hpp"
24 #include "units/unit.hpp"
25 #include "units/filter.hpp"
26 #include "units/map.hpp"
27 
28 static lg::log_domain log_engine("engine");
29 #define ERR_PF LOG_STREAM(err, log_engine)
30 
31 namespace pathfind {
32 
33 
34 namespace {
35  const std::string reversed_suffix = "-__REVERSED__";
36 }
37 
38 // This constructor is *only* meant for loading from saves
39 teleport_group::teleport_group(const config& cfg) : cfg_(cfg), reversed_(cfg["reversed"].to_bool(false)), id_(cfg["id"])
40 {
41  assert(cfg.has_attribute("id"));
42  assert(cfg.has_attribute("reversed"));
43 
44  assert(cfg_.child_count("source") == 1);
45  assert(cfg_.child_count("target") == 1);
46  assert(cfg_.child_count("filter") == 1);
47 }
48 
49 teleport_group::teleport_group(const vconfig& cfg, bool reversed) : cfg_(cfg.get_config()), reversed_(reversed), id_()
50 {
51  assert(cfg_.child_count("source") == 1);
52  assert(cfg_.child_count("target") == 1);
53  assert(cfg_.child_count("filter") == 1);
54  if (cfg["id"].empty()) {
56  } else {
57  id_ = cfg["id"].str();
58  if (reversed_) // Differentiate the reverse tunnel from the forward one
59  id_ += reversed_suffix;
60  }
61 }
62 
64 public:
66  : um_()
67  , gm_(&dc.map())
68  , tm_(&dc.teams())
69  , lbls_(&dc.hidden_label_categories())
70  {
71  static unit_map empty_unit_map;
72  um_ = &empty_unit_map;
73  }
74  const unit_map & units() const override { return *um_; }
75  const gamemap & map() const override { return *gm_; }
76  const std::vector<team> & teams() const override { return *tm_; }
77  const std::vector<std::string> & hidden_label_categories() const override { return *lbls_; }
78  std::vector<std::string>& hidden_label_categories() override { throw "Writable hidden label categories not supported in this context"; }
79 
80 private:
81  const unit_map * um_;
82  const gamemap * gm_;
83  const std::vector<team> * tm_;
84  const std::vector<std::string> * lbls_;
85 };
86 
88 public:
90  : dc_(fc.get_disp_context())
91  , tod_(&fc.get_tod_man())
92  , gd_(fc.get_game_data())
93  , lk_(fc.get_lua_kernel())
94  {}
95 
96  const display_context & get_disp_context() const override { return dc_; }
97  const tod_manager & get_tod_man() const override { return *tod_; }
98  const game_data * get_game_data() const override { return gd_; }
99  game_lua_kernel * get_lua_kernel() const override { return lk_; }
100 
101 private:
103  const tod_manager * tod_;
104  const game_data * gd_;
106 };
107 
109  teleport_pair& loc_pair
110  , const unit& u
111  , const bool ignore_units) const
112 {
114  assert(fc);
115 
116  if (ignore_units) {
118  }
119 
120  vconfig filter(cfg_.child_or_empty("filter"), true);
121  vconfig source(cfg_.child_or_empty("source"), true);
122  vconfig target(cfg_.child_or_empty("target"), true);
123  const unit_filter ufilt(filter); //Note: Don't use the ignore units filter context here, only for the terrain filters. (That's how it worked before the filter contexts were introduced)
124  if (ufilt.matches(u)) {
125  terrain_filter source_filter(source, fc);
126  source_filter.get_locations(reversed_ ? loc_pair.second : loc_pair.first, u);
127 
128  terrain_filter target_filter(target, fc);
129  target_filter.get_locations(reversed_ ? loc_pair.first : loc_pair.second, u);
130  }
131 
132  if (ignore_units) {
133  delete fc;
134  }
135 }
136 
137 const std::string& teleport_group::get_teleport_id() const {
138  return id_;
139 }
140 
142  return cfg_["always_visible"].to_bool(false);
143 }
144 
146  return cfg_["pass_allied_units"].to_bool(true);
147 }
148 
150  return cfg_["allow_vision"].to_bool(true);
151 }
152 
154  config retval = cfg_;
155  retval["saved"] = "yes";
156  retval["reversed"] = reversed_ ? "yes" : "no";
157  retval["id"] = id_;
158  return retval;
159 }
160 
162  const std::vector<teleport_group>& groups
163  , const unit& unit
164  , const team &viewing_team
165  , const bool see_all
166  , const bool ignore_units
167  , const bool check_vision)
168  : teleport_map_()
169  , sources_()
170  , targets_()
171 {
172 
173  for (const teleport_group& group : groups) {
174 
175  teleport_pair locations;
176 
177  if (check_vision && !group.allow_vision()) {
178  continue;
179  }
180 
181  group.get_teleport_pair(locations, unit, ignore_units);
182  if (!see_all && !group.always_visible() && viewing_team.is_enemy(unit.side())) {
183  teleport_pair filter_locs;
184  for (const map_location &loc : locations.first) {
185  if(!viewing_team.fogged(loc))
186  filter_locs.first.insert(loc);
187  }
188  for (const map_location &loc : locations.second) {
189  if(!viewing_team.fogged(loc))
190  filter_locs.second.insert(loc);
191  }
192  locations.first.swap(filter_locs.first);
193  locations.second.swap(filter_locs.second);
194  }
195 
196  if (!group.pass_allied_units() && !ignore_units && !check_vision) {
197  std::set<map_location>::iterator loc = locations.second.begin();
198  while(loc != locations.second.end()) {
200  if (see_all) {
201  u = resources::gameboard->units().find(*loc);
202  } else {
203  u = resources::gameboard->find_visible_unit(*loc, viewing_team);
204  }
205  if (u != resources::gameboard->units().end()) {
206  loc = locations.second.erase(loc);
207  } else {
208  ++loc;
209  }
210  }
211  }
212 
213  std::string teleport_id = group.get_teleport_id();
214  std::set<map_location>::iterator source_it = locations.first.begin();
215  for (; source_it != locations.first.end(); ++source_it ) {
216  if(teleport_map_.count(*source_it) == 0) {
217  std::set<std::string> id_set;
218  id_set.insert(teleport_id);
219  teleport_map_.emplace(*source_it, id_set);
220  } else {
221  (teleport_map_.find(*source_it)->second).insert(teleport_id);
222  }
223  }
224  sources_.emplace(teleport_id, locations.first);
225  targets_.emplace(teleport_id, locations.second);
226  }
227 }
228 
229 void teleport_map::get_adjacents(std::set<map_location>& adjacents, map_location loc) const {
230 
231  if (teleport_map_.count(loc) == 0) {
232  return;
233  } else {
234  const std::set<std::string>& keyset = (teleport_map_.find(loc)->second);
235  for(std::set<std::string>::const_iterator it = keyset.begin(); it != keyset.end(); ++it) {
236 
237  const std::set<map_location>& target = targets_.find(*it)->second;
238  adjacents.insert(target.begin(), target.end());
239  }
240  }
241 }
242 
243 void teleport_map::get_sources(std::set<map_location>& sources) const {
244 
245  std::map<std::string, std::set<map_location>>::const_iterator it;
246  for(it = sources_.begin(); it != sources_.end(); ++it) {
247  sources.insert(it->second.begin(), it->second.end());
248  }
249 }
250 
251 void teleport_map::get_targets(std::set<map_location>& targets) const {
252 
253  std::map<std::string, std::set<map_location>>::const_iterator it;
254  for(it = targets_.begin(); it != targets_.end(); ++it) {
255  targets.insert(it->second.begin(), it->second.end());
256  }
257 }
258 
259 
261  const team &viewing_team,
262  bool see_all, bool ignore_units, bool check_vision)
263 {
264  std::vector<teleport_group> groups;
265 
266  if (u.get_ability_bool("teleport")) {
267  for (const unit_ability & teleport : u.get_abilities("teleport")) {
268  const int tunnel_count = (teleport.first)->child_count("tunnel");
269  for(int i = 0; i < tunnel_count; ++i) {
270  config teleport_group_cfg = (teleport.first)->child("tunnel", i);
271  groups.emplace_back(vconfig(teleport_group_cfg, true), false);
272  }
273  }
274  }
275 
276  const std::vector<teleport_group>& global_groups = resources::tunnels->get();
277  groups.insert(groups.end(), global_groups.begin(), global_groups.end());
278 
279  return teleport_map(groups, u, viewing_team, see_all, ignore_units, check_vision);
280 }
281 
282 manager::manager(const config &cfg) : tunnels_(), id_(cfg["next_teleport_group_id"].to_int(0)) {
283  const int tunnel_count = cfg.child_count("tunnel");
284  for(int i = 0; i < tunnel_count; ++i) {
285  const config& t = cfg.child("tunnel", i);
286  if(!t["saved"].to_bool()) {
287  lg::wml_error() << "Do not use [tunnel] directly in a [scenario]. Use it in an [event] or [abilities] tag.\n";
288  continue;
289  }
290  const teleport_group tunnel(t);
291  this->add(tunnel);
292  }
293 }
294 
295 void manager::add(const teleport_group &group) {
296  tunnels_.push_back(group);
297 }
298 
299 void manager::remove(const std::string &id) {
301  for(;t != tunnels_.end();) {
302  if (t->get_teleport_id() == id || t->get_teleport_id() == id + reversed_suffix) {
303  t = tunnels_.erase(t);
304  } else {
305  ++t;
306  }
307  }
308 }
309 
310 const std::vector<teleport_group>& manager::get() const {
311  return tunnels_;
312 }
313 
315  config store;
316 
317  std::vector<teleport_group>::const_iterator tunnel = tunnels_.begin();
318  for(; tunnel != tunnels_.end(); ++tunnel) {
319  store.add_child("tunnel", tunnel->to_config());
320  }
321  store["next_teleport_group_id"] = std::to_string(id_);
322 
323  return store;
324 }
325 
326 std::string manager::next_unique_id() {
327  return std::to_string(++id_);
328 }
329 
330 
331 }//namespace pathfind
game_lua_kernel * get_lua_kernel() const override
Definition: teleport.cpp:99
std::map< std::string, std::set< map_location > > sources_
Definition: teleport.hpp:140
std::pair< std::set< map_location >, std::set< map_location > > teleport_pair
Definition: teleport.hpp:27
const ignore_units_display_context dc_
Definition: teleport.cpp:102
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:420
const game_data * get_game_data() const override
Definition: teleport.cpp:98
virtual const unit_map & units() const override
Definition: game_board.hpp:114
This class represents a single unit of a specific type.
Definition: unit.hpp:99
std::string next_unique_id()
Definition: teleport.cpp:326
const gamemap & map() const override
Definition: teleport.cpp:75
void get_targets(std::set< map_location > &targets) const
Definition: teleport.cpp:251
void remove(const std::string &id)
Definition: teleport.cpp:299
bool pass_allied_units() const
Definition: teleport.cpp:145
const std::vector< team > & teams() const override
Definition: teleport.cpp:76
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
unsigned child_count(config_key_type key) const
Definition: config.cpp:390
bool allow_vision() const
Definition: teleport.cpp:149
config to_config() const
Inherited from savegame_config.
Definition: teleport.cpp:314
const tod_manager & get_tod_man() const override
Definition: teleport.cpp:97
-file sdl_utils.hpp
config to_config() const
Inherited from savegame_config.
Definition: teleport.cpp:153
teleport_group(const config &cfg)
Definition: teleport.cpp:39
const unit_map & units() const override
Definition: teleport.cpp:74
const display_context & get_disp_context() const override
Definition: teleport.cpp:96
const std::string & get_teleport_id() const
Definition: teleport.cpp:137
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
std::pair< const config *, map_location > unit_ability
Definition: unit.hpp:48
filter_context * filter_con
Definition: resources.cpp:23
void get_teleport_pair(teleport_pair &loc_pair, const unit &u, const bool ignore_units) const
Definition: teleport.cpp:108
ignore_units_filter_context(const filter_context &fc)
Definition: teleport.cpp:89
game_board * gameboard
Definition: resources.cpp:20
Encapsulates the map of the game.
Definition: map.hpp:36
const std::vector< std::string > * lbls_
Definition: teleport.cpp:84
bool is_enemy(int n) const
Definition: team.hpp:243
std::vector< std::string > & hidden_label_categories() override
Definition: teleport.cpp:78
std::map< std::string, std::set< map_location > > targets_
Definition: teleport.hpp:141
const std::vector< teleport_group > & get() const
Definition: teleport.cpp:310
Encapsulates the map of the game.
Definition: location.hpp:42
unit_iterator find(std::size_t id)
Definition: map.cpp:311
bool get_ability_bool(const std::string &tag_name, const map_location &loc) const
Checks whether this unit currently possesses or is affected by a given ability.
Definition: abilities.cpp:143
void get_sources(std::set< map_location > &sources) const
Definition: teleport.cpp:243
std::map< map_location, std::set< std::string > > teleport_map_
Definition: teleport.hpp:139
std::size_t i
Definition: function.cpp:933
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:269
void get_adjacents(std::set< map_location > &adjacents, map_location loc) const
Definition: teleport.cpp:229
unit_ability_list get_abilities(const std::string &tag_name, const map_location &loc, const_attack_ptr weapon=nullptr, const_attack_ptr opp_weapon=nullptr) const
Gets the unit&#39;s active abilities of a particular type if it were on a specified location.
Definition: abilities.cpp:183
config & add_child(config_key_type key)
Definition: config.cpp:476
void add(const teleport_group &group)
Definition: teleport.cpp:295
manager(const config &cfg)
Definition: teleport.cpp:282
double t
Definition: astarsearch.cpp:64
static lg::log_domain log_engine("engine")
std::vector< teleport_group > tunnels_
Definition: teleport.hpp:183
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
const std::vector< team > * tm_
Definition: teleport.cpp:83
Standard logging facilities (interface).
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all, bool ignore_units, bool check_vision)
Definition: teleport.cpp:260
Container associating units to locations.
Definition: map.hpp:99
bool always_visible() const
Definition: teleport.cpp:141
ignore_units_display_context(const display_context &dc)
Definition: teleport.cpp:65
bool fogged(const map_location &loc) const
Definition: team.cpp:653
retval
Default window/dialog return values.
Definition: retval.hpp:28
int side() const
The side this unit belongs to.
Definition: unit.hpp:303
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:453
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
const std::vector< std::string > & hidden_label_categories() const override
Definition: teleport.cpp:77
pathfind::manager * tunnels
Definition: resources.cpp:31
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:168