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