The Battle for Wesnoth  1.17.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 static lg::log_domain log_wml("wml");
32 #define ERR_WML LOG_STREAM(err, log_wml)
33 
34 namespace pathfind {
35 
36 
37 namespace {
38  const std::string reversed_suffix = "-__REVERSED__";
39 }
40 
41 // This constructor is *only* meant for loading from saves
42 teleport_group::teleport_group(const config& cfg) : cfg_(cfg), reversed_(cfg["reversed"].to_bool(false)), id_(cfg["id"])
43 {
44  assert(cfg.has_attribute("id"));
45  assert(cfg.has_attribute("reversed"));
46 
47  assert(cfg_.child_count("source") == 1);
48  assert(cfg_.child_count("target") == 1);
49  assert(cfg_.child_count("filter") == 1);
50 }
51 
52 teleport_group::teleport_group(const vconfig& cfg, bool reversed) : cfg_(cfg.get_config()), reversed_(reversed), id_()
53 {
54  assert(cfg_.child_count("source") == 1);
55  assert(cfg_.child_count("target") == 1);
56  assert(cfg_.child_count("filter") == 1);
57  if (cfg["id"].empty()) {
59  } else {
60  id_ = cfg["id"].str();
61  if (reversed_) // Differentiate the reverse tunnel from the forward one
62  id_ += reversed_suffix;
63  }
64 }
65 
67 public:
69  : um_()
70  , gm_(&dc.map())
71  , tm_(&dc.teams())
72  , lbls_(&dc.hidden_label_categories())
73  {
74  static unit_map empty_unit_map;
75  um_ = &empty_unit_map;
76  }
77  const unit_map & units() const override { return *um_; }
78  const gamemap & map() const override { return *gm_; }
79  const std::vector<team> & teams() const override { return *tm_; }
80  const std::vector<std::string> & hidden_label_categories() const override { return *lbls_; }
81  std::vector<std::string>& hidden_label_categories() override { throw "Writable hidden label categories not supported in this context"; }
82 
83 private:
84  const unit_map * um_;
85  const gamemap * gm_;
86  const std::vector<team> * tm_;
87  const std::vector<std::string> * lbls_;
88 };
89 
91 public:
93  : dc_(fc.get_disp_context())
94  , tod_(&fc.get_tod_man())
95  , gd_(fc.get_game_data())
96  , lk_(fc.get_lua_kernel())
97  {}
98 
99  const display_context & get_disp_context() const override { return dc_; }
100  const tod_manager & get_tod_man() const override { return *tod_; }
101  const game_data * get_game_data() const override { return gd_; }
102  game_lua_kernel * get_lua_kernel() const override { return lk_; }
103 
104 private:
106  const tod_manager * tod_;
107  const game_data * gd_;
109 };
110 
112  teleport_pair& loc_pair
113  , const unit& u
114  , const bool ignore_units) const
115 {
117  assert(fc);
118 
119  if (ignore_units) {
121  }
122 
123  vconfig filter(cfg_.child_or_empty("filter"), true);
124  vconfig source(cfg_.child_or_empty("source"), true);
125  vconfig target(cfg_.child_or_empty("target"), true);
126  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)
127  if (ufilt.matches(u)) {
128  terrain_filter source_filter(source, fc, false);
129  source_filter.get_locations(reversed_ ? loc_pair.second : loc_pair.first, u);
130 
131  terrain_filter target_filter(target, fc, false);
132  target_filter.get_locations(reversed_ ? loc_pair.first : loc_pair.second, u);
133  }
134 
135  if (ignore_units) {
136  delete fc;
137  }
138 }
139 
140 const std::string& teleport_group::get_teleport_id() const {
141  return id_;
142 }
143 
145  return cfg_["always_visible"].to_bool(false);
146 }
147 
149  return cfg_["pass_allied_units"].to_bool(true);
150 }
151 
153  return cfg_["allow_vision"].to_bool(true);
154 }
155 
157  config retval = cfg_;
158  retval["saved"] = "yes";
159  retval["reversed"] = reversed_ ? "yes" : "no";
160  retval["id"] = id_;
161  return retval;
162 }
163 
165  const std::vector<teleport_group>& groups
166  , const unit& unit
167  , const team &viewing_team
168  , const bool see_all
169  , const bool ignore_units
170  , const bool check_vision)
171  : teleport_map_()
172  , sources_()
173  , targets_()
174 {
175 
176  for (const teleport_group& group : groups) {
177 
178  teleport_pair locations;
179 
180  if (check_vision && !group.allow_vision()) {
181  continue;
182  }
183 
184  group.get_teleport_pair(locations, unit, ignore_units);
185  if (!see_all && !group.always_visible() && viewing_team.is_enemy(unit.side())) {
186  teleport_pair filter_locs;
187  for (const map_location &loc : locations.first) {
188  if(!viewing_team.fogged(loc))
189  filter_locs.first.insert(loc);
190  }
191  for (const map_location &loc : locations.second) {
192  if(!viewing_team.fogged(loc))
193  filter_locs.second.insert(loc);
194  }
195  locations.first.swap(filter_locs.first);
196  locations.second.swap(filter_locs.second);
197  }
198 
199  if (!group.pass_allied_units() && !ignore_units && !check_vision) {
200  std::set<map_location>::iterator loc = locations.second.begin();
201  while(loc != locations.second.end()) {
203  if (see_all) {
204  u = resources::gameboard->units().find(*loc);
205  } else {
206  u = resources::gameboard->find_visible_unit(*loc, viewing_team);
207  }
208  if (u != resources::gameboard->units().end()) {
209  loc = locations.second.erase(loc);
210  } else {
211  ++loc;
212  }
213  }
214  }
215 
216  std::string teleport_id = group.get_teleport_id();
217  std::set<map_location>::iterator source_it = locations.first.begin();
218  for (; source_it != locations.first.end(); ++source_it ) {
219  if(teleport_map_.count(*source_it) == 0) {
220  std::set<std::string> id_set;
221  id_set.insert(teleport_id);
222  teleport_map_.emplace(*source_it, id_set);
223  } else {
224  (teleport_map_.find(*source_it)->second).insert(teleport_id);
225  }
226  }
227  sources_.emplace(teleport_id, locations.first);
228  targets_.emplace(teleport_id, locations.second);
229  }
230 }
231 
232 std::set<map_location> teleport_map::get_adjacents(map_location loc) const
233 {
234  const auto iter = teleport_map_.find(loc);
235  if(iter == teleport_map_.end()) {
236  return {};
237  }
238 
239  std::set<map_location> res;
240  for(const std::string& key : iter->second) {
241  const auto& target = targets_.find(key)->second;
242  res.insert(target.begin(), target.end());
243  }
244 
245  return res;
246 }
247 
248 std::set<map_location> teleport_map::get_sources() const
249 {
250  std::set<map_location> res;
251  for(const auto& src : sources_) {
252  res.insert(src.second.begin(), src.second.end());
253  }
254 
255  return res;
256 }
257 
258 std::set<map_location> teleport_map::get_targets() const
259 {
260  std::set<map_location> res;
261  for(const auto& tgt : targets_) {
262  res.insert(tgt.second.begin(), tgt.second.end());
263  }
264 
265  return res;
266 }
267 
269  const team &viewing_team,
270  bool see_all, bool ignore_units, bool check_vision)
271 {
272  std::vector<teleport_group> groups;
273 
274  for (const unit_ability & teleport : u.get_abilities("teleport")) {
275  const int tunnel_count = (teleport.ability_cfg)->child_count("tunnel");
276  for(int i = 0; i < tunnel_count; ++i) {
277  config teleport_group_cfg = (teleport.ability_cfg)->child("tunnel", i);
278  groups.emplace_back(vconfig(teleport_group_cfg, true), false);
279  }
280  }
281 
282  const std::vector<teleport_group>& global_groups = resources::tunnels->get();
283  groups.insert(groups.end(), global_groups.begin(), global_groups.end());
284 
285  return teleport_map(groups, u, viewing_team, see_all, ignore_units, check_vision);
286 }
287 
288 manager::manager(const config &cfg) : tunnels_(), id_(cfg["next_teleport_group_id"].to_int(0)) {
289  const int tunnel_count = cfg.child_count("tunnel");
290  for(int i = 0; i < tunnel_count; ++i) {
291  const config& t = cfg.child("tunnel", i);
292  if(!t["saved"].to_bool()) {
293  lg::log_to_chat() << "Do not use [tunnel] directly in a [scenario]. Use it in an [event] or [abilities] tag.\n";
294  ERR_WML << "Do not use [tunnel] directly in a [scenario]. Use it in an [event] or [abilities] tag.";
295  continue;
296  }
297  const teleport_group tunnel(t);
298  this->add(tunnel);
299  }
300 }
301 
302 void manager::add(const teleport_group &group) {
303  tunnels_.push_back(group);
304 }
305 
306 void manager::remove(const std::string &id) {
308  for(;t != tunnels_.end();) {
309  if (t->get_teleport_id() == id || t->get_teleport_id() == id + reversed_suffix) {
310  t = tunnels_.erase(t);
311  } else {
312  ++t;
313  }
314  }
315 }
316 
317 const std::vector<teleport_group>& manager::get() const {
318  return tunnels_;
319 }
320 
322  config store;
323 
324  std::vector<teleport_group>::const_iterator tunnel = tunnels_.begin();
325  for(; tunnel != tunnels_.end(); ++tunnel) {
326  store.add_child("tunnel", tunnel->to_config());
327  }
328  store["next_teleport_group_id"] = std::to_string(id_);
329 
330  return store;
331 }
332 
333 std::string manager::next_unique_id() {
334  return std::to_string(++id_);
335 }
336 
337 
338 }//namespace pathfind
game_lua_kernel * get_lua_kernel() const override
Definition: teleport.cpp:102
std::map< std::string, std::set< map_location > > sources_
Definition: teleport.hpp:138
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:105
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:418
const game_data * get_game_data() const override
Definition: teleport.cpp:101
virtual const unit_map & units() const override
Definition: game_board.hpp:111
This class represents a single unit of a specific type.
Definition: unit.hpp:120
std::string next_unique_id()
Definition: teleport.cpp:333
const gamemap & map() const override
Definition: teleport.cpp:78
void remove(const std::string &id)
Definition: teleport.cpp:306
bool pass_allied_units() const
Definition: teleport.cpp:148
const std::vector< team > & teams() const override
Definition: teleport.cpp:79
bool has_attribute(config_key_type key) const
Definition: config.cpp:210
unsigned child_count(config_key_type key) const
Definition: config.cpp:388
bool allow_vision() const
Definition: teleport.cpp:152
config to_config() const
Inherited from savegame_config.
Definition: teleport.cpp:321
const tod_manager & get_tod_man() const override
Definition: teleport.cpp:100
config to_config() const
Inherited from savegame_config.
Definition: teleport.cpp:156
teleport_group(const config &cfg)
Definition: teleport.cpp:42
const unit_map & units() const override
Definition: teleport.cpp:77
std::set< map_location > get_adjacents(map_location loc) const
Definition: teleport.cpp:232
const display_context & get_disp_context() const override
Definition: teleport.cpp:99
const std::string & get_teleport_id() const
Definition: teleport.cpp:140
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:71
Data typedef for unit_ability_list.
Definition: unit.hpp:39
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:111
ignore_units_filter_context(const filter_context &fc)
Definition: teleport.cpp:92
game_board * gameboard
Definition: resources.cpp:20
std::set< map_location > get_sources() const
Returns the locations that are an entrance of the tunnel.
Definition: teleport.cpp:248
Encapsulates the map of the game.
Definition: map.hpp:170
const std::vector< std::string > * lbls_
Definition: teleport.cpp:87
bool is_enemy(int n) const
Definition: team.hpp:254
std::vector< std::string > & hidden_label_categories() override
Definition: teleport.cpp:81
std::map< std::string, std::set< map_location > > targets_
Definition: teleport.hpp:139
const std::vector< teleport_group > & get() const
Definition: teleport.cpp:317
Encapsulates the map of the game.
Definition: location.hpp:37
unit_iterator find(std::size_t id)
Definition: map.cpp:309
std::map< map_location, std::set< std::string > > teleport_map_
Definition: teleport.hpp:137
std::size_t i
Definition: function.cpp:940
config & add_child(config_key_type key)
Definition: config.cpp:504
void add(const teleport_group &group)
Definition: teleport.cpp:302
manager(const config &cfg)
Definition: teleport.cpp:288
#define ERR_WML
Definition: teleport.cpp:32
double t
Definition: astarsearch.cpp:64
static lg::log_domain log_engine("engine")
std::vector< teleport_group > tunnels_
Definition: teleport.hpp:181
A variable-expanding proxy for the config class.
Definition: variable.hpp:44
const std::vector< team > * tm_
Definition: teleport.cpp:86
Standard logging facilities (interface).
std::set< map_location > get_targets() const
Returns the locations that are an exit of the tunnel.
Definition: teleport.cpp:258
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:268
Container associating units to locations.
Definition: map.hpp:97
bool always_visible() const
Definition: teleport.cpp:144
ignore_units_display_context(const display_context &dc)
Definition: teleport.cpp:68
bool fogged(const map_location &loc) const
Definition: team.cpp:660
static lg::log_domain log_wml("wml")
retval
Default window/dialog return values.
Definition: retval.hpp:28
int side() const
The side this unit belongs to.
Definition: unit.hpp:333
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:481
unit_ability_list get_abilities(const std::string &tag_name, const map_location &loc) const
Gets the unit&#39;s active abilities of a particular type if it were on a specified location.
Definition: abilities.cpp:187
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
const std::vector< std::string > & hidden_label_categories() const override
Definition: teleport.cpp:80
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:182
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
Definition: log.cpp:288