The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
teleport.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2010 - 2025
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"
23#include "team.hpp"
24#include "terrain/filter.hpp"
25#include "units/unit.hpp"
26#include "units/filter.hpp"
27#include "units/map.hpp"
28#include "wml_exception.hpp"
29
30static lg::log_domain log_engine("engine");
31#define ERR_PF LOG_STREAM(err, log_engine)
32
33static lg::log_domain log_wml("wml");
34#define ERR_WML LOG_STREAM(err, log_wml)
35
36namespace pathfind {
37
38
39namespace {
40 const std::string reversed_suffix = "-__REVERSED__";
41}
42
43// This constructor is *only* meant for loading from saves
44teleport_group::teleport_group(const config& cfg) : cfg_(cfg), reversed_(cfg["reversed"].to_bool(false)), id_(cfg["id"])
45{
47 VALIDATE(cfg.has_attribute("reversed"), missing_mandatory_wml_key("tunnel", "reversed"));
48
49 VALIDATE(cfg_.child_count("source") == 1, "The tunnel should have only one 'source' child.");
50 VALIDATE(cfg_.child_count("target") == 1, "The tunnel should have only one 'target' child.");
51 VALIDATE(cfg_.child_count("filter") == 1, "The tunnel should have only one 'filter' child.");
52}
53
54teleport_group::teleport_group(const vconfig& cfg, bool reversed) : cfg_(cfg.get_config()), reversed_(reversed), id_()
55{
56 VALIDATE(cfg_.child_count("source") == 1, "The tunnel should have only one 'source' child.");
57 VALIDATE(cfg_.child_count("target") == 1, "The tunnel should have only one 'target' child.");
58 VALIDATE(cfg_.child_count("filter") == 1, "The tunnel should have only one 'filter' child.");
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
69public:
71 : um_()
72 , gm_(&dc.map())
73 , tm_(&dc.teams())
75 {
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
85private:
86 const unit_map * um_;
87 const gamemap * gm_;
88 const std::vector<team> * tm_;
89 const std::vector<std::string> * lbls_;
90};
91
93public:
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
106private:
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 utils::optional<ignore_units_filter_context> ignore_context;
122 if (ignore_units) {
123 ignore_context.emplace(*resources::filter_con);
124 fc = &ignore_context.value();
125 }
126
127 vconfig filter(cfg_.child_or_empty("filter"), true);
128 vconfig source(cfg_.child_or_empty("source"), true);
129 vconfig target(cfg_.child_or_empty("target"), true);
130 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)
131 if (ufilt.matches(u)) {
132 terrain_filter source_filter(source, fc, false);
133 source_filter.get_locations(reversed_ ? loc_pair.second : loc_pair.first, u);
134
135 terrain_filter target_filter(target, fc, false);
136 target_filter.get_locations(reversed_ ? loc_pair.first : loc_pair.second, u);
137 }
138}
139
140const 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) {
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::set<map_location>::iterator source_it = locations.first.begin();
217 for (; source_it != locations.first.end(); ++source_it ) {
218 auto map_it = teleport_map_.find(*source_it);
219
220 if(map_it == teleport_map_.end()) {
221 teleport_map_.emplace(*source_it, std::unordered_set(locations.second.begin(), locations.second.end()));
222 } else {
223 map_it->second.insert(locations.second.begin(), locations.second.end());
224 }
225 }
226 sources_.insert(locations.first.begin(), locations.first.end());
227 targets_.insert(locations.second.begin(), locations.second.end());
228 }
229}
230
231const std::unordered_set<map_location>& teleport_map::get_adjacents(map_location loc) const
232{
233 const auto iter = teleport_map_.find(loc);
234 if(iter == teleport_map_.end()) {
235 return empty_set_;
236 }
237
238 return iter->second;
239}
240
241const std::unordered_set<map_location>& teleport_map::get_sources() const
242{
243 return sources_;
244}
245
246const std::unordered_set<map_location>& teleport_map::get_targets() const
247{
248 return targets_;
249}
250
252 const team &viewing_team,
253 bool see_all, bool ignore_units, bool check_vision)
254{
255 std::vector<teleport_group> groups;
256
257 for (const active_ability & teleport : u.get_abilities("teleport")) {
258 const int tunnel_count = teleport.ability_cfg().child_count("tunnel");
259 for(int i = 0; i < tunnel_count; ++i) {
260 config teleport_group_cfg = teleport.ability_cfg().mandatory_child("tunnel", i);
261 groups.emplace_back(vconfig(teleport_group_cfg, true), false);
262 }
263 }
264
265 const std::vector<teleport_group>& global_groups = resources::tunnels->get();
266 groups.insert(groups.end(), global_groups.begin(), global_groups.end());
267
268 return teleport_map(groups, u, viewing_team, see_all, ignore_units, check_vision);
269}
270
271manager::manager(const config &cfg) : tunnels_(), id_(cfg["next_teleport_group_id"].to_int(0)) {
272 const int tunnel_count = cfg.child_count("tunnel");
273 for(int i = 0; i < tunnel_count; ++i) {
274 const config& t = cfg.mandatory_child("tunnel", i);
275 if(!t["saved"].to_bool()) {
276 lg::log_to_chat() << "Do not use [tunnel] directly in a [scenario]. Use it in an [event] or [abilities] tag.\n";
277 ERR_WML << "Do not use [tunnel] directly in a [scenario]. Use it in an [event] or [abilities] tag.";
278 continue;
279 }
280 const teleport_group tunnel(t);
281 this->add(tunnel);
282 }
283}
284
285void manager::add(const teleport_group &group) {
286 tunnels_.push_back(group);
287}
288
289void manager::remove(const std::string &id) {
290 std::vector<teleport_group>::iterator t = tunnels_.begin();
291 for(;t != tunnels_.end();) {
292 if (t->get_teleport_id() == id || t->get_teleport_id() == id + reversed_suffix) {
293 t = tunnels_.erase(t);
294 } else {
295 ++t;
296 }
297 }
298}
299
300const std::vector<teleport_group>& manager::get() const {
301 return tunnels_;
302}
303
305 config store;
306
307 std::vector<teleport_group>::const_iterator tunnel = tunnels_.begin();
308 for(; tunnel != tunnels_.end(); ++tunnel) {
309 store.add_child("tunnel", tunnel->to_config());
310 }
311 store["next_teleport_group_id"] = std::to_string(id_);
312
313 return store;
314}
315
317 return std::to_string(++id_);
318}
319
320
321}//namespace pathfind
map_location loc
Definition move.cpp:172
double t
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
config & add_child(std::string_view key)
Definition config.cpp:436
bool has_attribute(std::string_view key) const
Definition config.cpp:157
std::size_t child_count(std::string_view key) const
Definition config.cpp:292
const config & child_or_empty(std::string_view key) const
Returns the first child with the given key, or an empty config if there is none.
Definition config.cpp:390
config & mandatory_child(std::string_view key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition config.cpp:362
Abstract class for exposing game data that doesn't depend on the GUI, however which for historical re...
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
virtual const unit_map & units() const override
Encapsulates the map of the game.
Definition map.hpp:176
const unit_map & units() const override
Definition teleport.cpp:79
const std::vector< team > * tm_
Definition teleport.cpp:88
const std::vector< std::string > * lbls_
Definition teleport.cpp:89
const std::vector< team > & teams() const override
Definition teleport.cpp:81
ignore_units_display_context(const display_context &dc)
Definition teleport.cpp:70
std::vector< std::string > & hidden_label_categories() override
Definition teleport.cpp:83
const gamemap & map() const override
Definition teleport.cpp:80
const std::vector< std::string > & hidden_label_categories() const override
Definition teleport.cpp:82
const ignore_units_display_context dc_
Definition teleport.cpp:107
const display_context & get_disp_context() const override
Definition teleport.cpp:101
game_lua_kernel * get_lua_kernel() const override
Definition teleport.cpp:104
const tod_manager & get_tod_man() const override
Definition teleport.cpp:102
ignore_units_filter_context(const filter_context &fc)
Definition teleport.cpp:94
const game_data * get_game_data() const override
Definition teleport.cpp:103
config to_config() const
Inherited from savegame_config.
Definition teleport.cpp:304
void add(const teleport_group &group)
Definition teleport.cpp:285
std::vector< teleport_group > tunnels_
Definition teleport.hpp:187
void remove(const std::string &id)
Definition teleport.cpp:289
const std::vector< teleport_group > & get() const
Definition teleport.cpp:300
manager(const config &cfg)
Definition teleport.cpp:271
std::string next_unique_id()
Definition teleport.cpp:316
config to_config() const
Inherited from savegame_config.
Definition teleport.cpp:156
bool always_visible() const
Definition teleport.cpp:144
const std::string & get_teleport_id() const
Definition teleport.cpp:140
teleport_group(const config &cfg)
Definition teleport.cpp:44
bool pass_allied_units() const
Definition teleport.cpp:148
void get_teleport_pair(teleport_pair &loc_pair, const unit &u, const bool ignore_units) const
Definition teleport.cpp:113
bool allow_vision() const
Definition teleport.cpp:152
const std::unordered_set< map_location > & get_sources() const
Returns the locations that are an entrance of the tunnel.
Definition teleport.cpp:241
std::unordered_set< map_location > targets_
Definition teleport.hpp:144
std::unordered_map< map_location, std::unordered_set< map_location > > teleport_map_
Definition teleport.hpp:142
std::unordered_set< map_location > sources_
Definition teleport.hpp:143
const std::unordered_set< map_location > & get_targets() const
Returns the locations that are an exit of the tunnel.
Definition teleport.cpp:246
std::unordered_set< map_location > empty_set_
Definition teleport.hpp:145
const std::unordered_set< map_location > & get_adjacents(map_location loc) const
Definition teleport.cpp:231
This class stores all the data for a single 'side' (in game nomenclature).
Definition team.hpp:74
bool is_enemy(int n) const
Definition team.hpp:270
bool fogged(const map_location &loc) const
Definition team.cpp:645
bool matches(const unit &u, const map_location &loc) const
Determine if *this matches filter at a specified location.
Definition filter.hpp:123
Container associating units to locations.
Definition map.hpp:98
unit_iterator find(std::size_t id)
Definition map.cpp:302
This class represents a single unit of a specific type.
Definition unit.hpp:39
A variable-expanding proxy for the config class.
Definition variable.hpp:45
#define ERR_WML
const config * cfg
active_ability_list get_abilities(const std::string &tag_name, const map_location &loc) const
Gets the unit's active abilities of a particular type if it were on a specified location.
int side() const
The side this unit belongs to.
Definition unit.hpp:249
Standard logging facilities (interface).
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
Definition log.cpp:550
std::pair< std::set< map_location >, std::set< map_location > > teleport_pair
Definition teleport.hpp:32
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:251
game_board * gameboard
Definition resources.cpp:20
pathfind::manager * tunnels
Definition resources.cpp:31
filter_context * filter_con
Definition resources.cpp:23
Data typedef for active_ability_list.
Encapsulates the map of the game.
Definition location.hpp:46
static lg::log_domain log_engine("engine")
static lg::log_domain log_wml("wml")
std::string missing_mandatory_wml_key(const std::string &section, const std::string &key, const std::string &primary_key, const std::string &primary_value)
Returns a standard message for a missing wml key (attribute).
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
#define i