The Battle for Wesnoth  1.19.14+dev
filter.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2025
3  by David White <dave@whitevine.net>
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 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
18 #include "config.hpp"
19 #include "display_context.hpp"
20 #include "filter_context.hpp"
21 #include "game_config.hpp"
22 #include "game_data.hpp"
23 #include "log.hpp"
24 #include "map/map.hpp"
25 #include "side_filter.hpp"
26 #include "team.hpp"
27 #include "terrain/filter.hpp"
28 #include "tod_manager.hpp"
29 #include "units/unit.hpp"
30 #include "units/filter.hpp"
31 #include "variable.hpp"
33 #include "formula/formula.hpp"
37 
38 #include <boost/range/adaptor/transformed.hpp>
39 
40 static lg::log_domain log_engine("engine");
41 #define ERR_NG LOG_STREAM(err, log_engine)
42 #define WRN_NG LOG_STREAM(warn, log_engine)
43 
44 static lg::log_domain log_wml("wml");
45 #define ERR_WML LOG_STREAM(err, log_wml)
46 
48 {
49 }
50 
51 terrain_filter::terrain_filter(const vconfig& cfg, const filter_context* fc, const bool flat_tod)
52  : cfg_(cfg)
53  , fc_(fc)
54  , cache_()
55  , max_loop_(game_config::max_loop)
56  , flat_(flat_tod)
57 {
58 }
59 
60 terrain_filter::terrain_filter(const vconfig& cfg, const terrain_filter& original)
61  : cfg_(cfg)
62  , fc_(original.fc_)
63  , cache_()
64  , max_loop_(original.max_loop_)
65  , flat_(original.flat_)
66 {
67 }
68 
69 terrain_filter::terrain_filter(const terrain_filter& other)
70  : xy_pred() // We should construct this too, since it has no datamembers use the default constructor.
71  , cfg_(other.cfg_)
72  , fc_(other.fc_)
73  , cache_()
74  , max_loop_(other.max_loop_)
75  , flat_(other.flat_)
76 {
77 }
78 
79 terrain_filter& terrain_filter::operator=(const terrain_filter& other)
80 {
81  // Use copy constructor to make sure we are coherent
82  if (this != &other) {
83  this->~terrain_filter();
84  new (this) terrain_filter(other) ;
85  }
86  return *this ;
87 }
88 
90  : parsed_terrain(nullptr)
91  , adjacent_matches(nullptr)
92  , adjacent_match_cache()
93  , ufilter_()
94 {
95 }
96 
97 bool terrain_filter::match_internal(const map_location& loc, const unit* ref_unit, const bool ignore_xy) const
98 {
99  if (!this->fc_->get_disp_context().map().on_board_with_border(loc)) {
100  return false;
101  }
102 
103  std::string lua_function = cfg_["lua_function"];
104  if (!lua_function.empty() && fc_->get_lua_kernel()) {
105  if (!fc_->get_lua_kernel()->run_filter(lua_function.c_str(), loc)) {
106  return false;
107  }
108  }
109 
110  //Filter Areas
111  if (cfg_.has_attribute("area") &&
112  fc_->get_tod_man().get_area_by_id(cfg_["area"]).count(loc) == 0)
113  return false;
114 
115  if(cfg_.has_attribute("gives_income") &&
116  cfg_["gives_income"].to_bool() != fc_->get_disp_context().map().is_village(loc))
117  return false;
118 
119  if(cfg_.has_attribute("terrain")) {
120  if(cache_.parsed_terrain == nullptr) {
121  cache_.parsed_terrain.reset(new t_translation::ter_match(std::string_view(cfg_["terrain"].str())));
122  }
123  if(!cache_.parsed_terrain->is_empty) {
126  return false;
127  }
128  }
129  }
130 
131  //Allow filtering on location ranges
132  if (!ignore_xy) {
133  if (!loc.matches_range(cfg_["x"], cfg_["y"])) {
134  return false;
135  }
136  //allow filtering by searching a stored variable of locations
137  if (cfg_.has_attribute("find_in")) {
138  if (const game_data * gd = fc_->get_game_data()) {
139  try
140  {
141  variable_access_const vi = gd->get_variable_access_read(cfg_["find_in"]);
142 
143  bool found = false;
144  for (const config &cfg : vi.as_array()) {
145  if (map_location(cfg, nullptr) == loc) {
146  found = true;
147  break;
148  }
149  }
150  if (!found) return false;
151  }
152  catch (const invalid_variablename_exception&)
153  {
154  return false;
155  }
156  }
157  }
158  if (cfg_.has_attribute("location_id")) {
159  std::set<map_location> matching_locs;
160  for(const auto& id : utils::split(cfg_["location_id"])) {
162  if(test_loc.valid()) {
163  matching_locs.insert(test_loc);
164  }
165  }
166  if (matching_locs.count(loc) == 0) {
167  return false;
168  }
169  }
170  }
171  //Allow filtering on unit
172  if(cfg_.has_child("filter")) {
174  if (!u.valid())
175  return false;
176  if (!cache_.ufilter_) {
177  cache_.ufilter_.reset(new unit_filter(cfg_.child("filter").make_safe()));
178  cache_.ufilter_->set_use_flat_tod(flat_);
179  }
180  if (!cache_.ufilter_->matches(*u, loc))
181  return false;
182  }
183 
184  // Allow filtering on visibility to a side
185  if (cfg_.has_child("filter_vision")) {
186  const vconfig::child_list& vis_filt = cfg_.get_children("filter_vision");
187  vconfig::child_list::const_iterator i, i_end = vis_filt.end();
188  for (i = vis_filt.begin(); i != i_end; ++i) {
189  bool visible = (*i)["visible"].to_bool(true);
190  bool respect_fog = (*i)["respect_fog"].to_bool(true);
191 
192  side_filter ssf(*i, fc_);
193  std::vector<int> sides = ssf.get_teams();
194 
195  bool found = false;
196  for (const int side : sides) {
197  const team &viewing_team = fc_->get_disp_context().get_team(side);
198  bool viewer_sees = respect_fog ? !viewing_team.fogged(loc) : !viewing_team.shrouded(loc);
199  if (visible == viewer_sees) {
200  found = true;
201  break;
202  }
203  }
204  if (!found) {return false;}
205  }
206  }
207 
208  //Allow filtering on adjacent locations
209  if(cfg_.has_child("filter_adjacent_location")) {
210  const auto adjacent = get_adjacent_tiles(loc);
211  const vconfig::child_list& adj_cfgs = cfg_.get_children("filter_adjacent_location");
212  vconfig::child_list::const_iterator i, i_end, i_begin = adj_cfgs.begin();
213  for (i = i_begin, i_end = adj_cfgs.end(); i != i_end; ++i) {
214  int match_count = 0;
215  vconfig::child_list::difference_type index = i - i_begin;
216  std::vector<map_location::direction> dirs = (*i).has_attribute("adjacent")
218  std::vector<map_location::direction>::const_iterator j, j_end = dirs.end();
219  for (j = dirs.begin(); j != j_end; ++j) {
220  const map_location &adj = adjacent[static_cast<int>(*j)];
221  if (fc_->get_disp_context().map().on_board(adj)) {
222  if(cache_.adjacent_matches == nullptr) {
223  while(index >= std::distance(cache_.adjacent_match_cache.begin(), cache_.adjacent_match_cache.end())) {
224  const vconfig& adj_cfg = adj_cfgs[cache_.adjacent_match_cache.size()];
225  std::pair<terrain_filter, std::map<map_location,bool>> amc_pair(
226  terrain_filter(adj_cfg, *this),
227  std::map<map_location,bool>());
228  cache_.adjacent_match_cache.push_back(amc_pair);
229  }
230  terrain_filter &amc_filter = cache_.adjacent_match_cache[index].first;
231  std::map<map_location,bool> &amc = cache_.adjacent_match_cache[index].second;
232  std::map<map_location,bool>::iterator lookup = amc.find(adj);
233  if(lookup == amc.end()) {
234  if(amc_filter(adj)) {
235  amc[adj] = true;
236  ++match_count;
237  } else {
238  amc[adj] = false;
239  }
240  } else if(lookup->second) {
241  ++match_count;
242  }
243  } else {
244  assert(index < std::distance(cache_.adjacent_matches->begin(), cache_.adjacent_matches->end()));
245  std::set<map_location> &amc = (*cache_.adjacent_matches)[index];
246  if(amc.find(adj) != amc.end()) {
247  ++match_count;
248  }
249  }
250  }
251  }
252  static std::vector<std::pair<int,int>> default_counts = utils::parse_ranges_unsigned("1-6");
253  std::vector<std::pair<int,int>> counts = (*i).has_attribute("count")
255  if(!in_ranges(match_count, counts)) {
256  return false;
257  }
258  }
259  }
260 
261  const t_string& t_tod_type = cfg_["time_of_day"];
262  const t_string& t_tod_id = cfg_["time_of_day_id"];
263  const std::string& tod_type = t_tod_type;
264  const std::string& tod_id = t_tod_id;
265  if(!tod_type.empty() || !tod_id.empty()) {
266  // creating a time_of_day is expensive, only do it if we will use it
267  const time_of_day& tod = flat_
270 
271  if(!tod_type.empty()) {
272  const std::vector<std::string>& vals = utils::split(tod_type);
273  if(tod.lawful_bonus<0) {
274  if(!utils::contains(vals, unit_alignments::chaotic)) {
275  return false;
276  }
277  } else if(tod.lawful_bonus>0) {
278  if(!utils::contains(vals, unit_alignments::lawful)) {
279  return false;
280  }
281  } else if(
282  !utils::contains(vals, unit_alignments::neutral) &&
283  !utils::contains(vals, unit_alignments::liminal)
284  ) {
285  return false;
286  }
287  }
288 
289  if(!tod_id.empty()) {
290  if(tod_id != tod.id) {
291  if(utils::contains(tod_id, ',')
292  && std::search(tod_id.begin(), tod_id.end(), tod.id.begin(), tod.id.end()) != tod_id.end()
293  ) {
294  if(!utils::contains(utils::split(tod_id), tod.id)) {
295  return false;
296  }
297  } else {
298  return false;
299  }
300  }
301  }
302  }
303 
304  //allow filtering on owner (for villages)
305  const config::attribute_value &owner_side = cfg_["owner_side"];
306  const vconfig& filter_owner = cfg_.child("filter_owner");
307  if(!filter_owner.null()) {
308  if(!owner_side.empty()) {
309  WRN_NG << "duplicate side information in a SLF, ignoring inline owner_side=";
310  }
312  return false;
313  side_filter ssf(filter_owner, fc_);
314  const std::vector<int>& sides = ssf.get_teams();
315  bool found = false;
316  if(sides.empty() && fc_->get_disp_context().village_owner(loc) == 0)
317  found = true;
318  for(const int side : sides) {
320  found = true;
321  break;
322  }
323  }
324  if(!found)
325  return false;
326  }
327  else if(!owner_side.empty()) {
328  const int side_num = owner_side.to_int(0);
329  if(fc_->get_disp_context().village_owner(loc) != side_num) {
330  return false;
331  }
332  }
333 
334  if(cfg_.has_attribute("formula")) {
335  try {
337  wfl::map_formula_callable callable(main.fake_ptr());
338  if(ref_unit) {
339  auto ref = std::make_shared<wfl::unit_callable>(*ref_unit);
340  callable.add("teleport_unit", wfl::variant(ref));
341  // It's not destroyed upon scope exit because the variant holds a reference
342  }
344  const wfl::formula form(cfg_["formula"], &symbols);
345  if(!form.evaluate(callable).as_bool()) {
346  return false;
347  }
348  return true;
349  } catch(const wfl::formula_error& e) {
350  lg::log_to_chat() << "Formula error in location filter: " << e.type << " at " << e.filename << ':' << e.line << ")\n";
351  ERR_WML << "Formula error in location filter: " << e.type << " at " << e.filename << ':' << e.line << ")";
352  // Formulae with syntax errors match nothing
353  return false;
354  }
355  }
356 
357  return true;
358 }
359 
360 class filter_with_unit : public xy_pred {
361  const terrain_filter& filt_;
362  const unit& ref_;
363 public:
364  filter_with_unit(const terrain_filter& filt, const unit& ref) : filt_(filt), ref_(ref) {}
365  bool operator()(const map_location& loc) const override {
366  return filt_.match(loc, ref_);
367  }
368 };
369 
370 bool terrain_filter::match_impl(const map_location& loc, const unit* ref_unit) const
371 {
372  if(cfg_["x"] == "recall" && cfg_["y"] == "recall") {
373  return !fc_->get_disp_context().map().on_board(loc);
374  }
375  std::set<map_location> hexes;
376  std::vector<map_location> loc_vec(1, loc);
377 
378  std::unique_ptr<scoped_wml_variable> ref_unit_var;
379  if(ref_unit) {
380  if(fc_->get_disp_context().map().on_board(ref_unit->get_location())) {
381  ref_unit_var.reset(new scoped_xy_unit("teleport_unit", ref_unit->get_location(), fc_->get_disp_context().units()));
382  } else {
383  // Possible TODO: Support recall list units?
384  }
385  }
386 
387  //handle radius
388  std::size_t radius = cfg_["radius"].to_size_t(0);
389  if(radius > max_loop_) {
390  ERR_NG << "terrain_filter: radius greater than " << max_loop_
391  << ", restricting";
392  radius = max_loop_;
393  }
394  if ( radius == 0 )
395  hexes.insert(loc_vec.begin(), loc_vec.end());
396  else if ( cfg_.has_child("filter_radius") ) {
397  terrain_filter r_filter(cfg_.child("filter_radius"), *this);
398  if(ref_unit) {
399  get_tiles_radius(fc_->get_disp_context().map(), loc_vec, radius, hexes, false, filter_with_unit(r_filter, *ref_unit));
400  } else {
401  get_tiles_radius(fc_->get_disp_context().map(), loc_vec, radius, hexes, false, r_filter);
402  }
403  } else {
404  get_tiles_radius(fc_->get_disp_context().map(), loc_vec, radius, hexes);
405  }
406 
407  std::size_t loop_count = 0;
408  std::set<map_location>::const_iterator i;
409  for(i = hexes.begin(); i != hexes.end(); ++i) {
410  bool matches = match_internal(*i, ref_unit, false);
411 
412  // Handle [and], [or], and [not] with in-order precedence
413  for(const auto& [key, filter] : cfg_.all_ordered()) {
414  // Handle [and]
415  if(key == "and") {
416  matches = matches && terrain_filter(filter, *this).match_impl(*i, ref_unit);
417  }
418  // Handle [or]
419  else if(key == "or") {
420  matches = matches || terrain_filter(filter, *this).match_impl(*i, ref_unit);
421  }
422  // Handle [not]
423  else if(key == "not") {
424  matches = matches && !terrain_filter(filter, *this).match_impl(*i, ref_unit);
425  }
426  }
427 
428  if(matches) {
429  return true;
430  }
431  if(++loop_count > max_loop_) {
432  std::set<map_location>::const_iterator temp = i;
433  if(++temp != hexes.end()) {
434  ERR_NG << "terrain_filter: loop count greater than " << max_loop_
435  << ", aborting";
436  break;
437  }
438  }
439  }
440  return false;
441 }
442 //using a class to be able to firen it in terrain_filter
444 {
445 public:
446  using location_set = std::set<map_location>;
447  struct no_start_set_yet {};
448  struct no_filter
449  {
450  bool operator()(const map_location&) const { return true; }
451  };
452 
453  template<typename T, typename F1, typename F2, typename F3>
454  static void filter_final(T&& src, location_set& dest, const terrain_filter&, const F1& f1, const F2& f2, const F3& f3)
455  {
456  for (map_location loc : src) {
457  if (f1(loc) && f2(loc) && f3(loc)) {
458  dest.insert(loc);
459  }
460  }
461  }
462 
463  template<typename T, typename F1, typename F2>
464  static void filter_special_loc(T&& src, location_set& dest, const terrain_filter& filter, const F1& f1, const F2& f2)
465  {
466  if (filter.cfg_.has_attribute("location_id")) {
467  std::set<map_location> matching_locs;
468  for(const auto& id : utils::split(filter.cfg_["location_id"])) {
469  map_location test_loc = filter.fc_->get_disp_context().map().special_location(id);
470  if(test_loc.valid()) {
471  matching_locs.insert(test_loc);
472  }
473  }
474  filter_final(src, dest, filter, f1, f2, [matching_locs](const map_location& loc) { return matching_locs.count(loc) > 0; });
475  }
476  else {
477  filter_final(src, dest, filter, f1, f2, no_filter());
478  }
479  }
480 
481  template<typename T, typename F1>
482  static void filter_area(T&& src, location_set& dest, const terrain_filter& filter, const F1& f1)
483  {
484  if (filter.cfg_.has_attribute("area")) {
485  const std::set<map_location>& area = filter.fc_->get_tod_man().get_area_by_id(filter.cfg_["area"]);
486  filter_special_loc(src, dest, filter, f1, [&area](const map_location& loc) { return area.find(loc) != area.end(); });
487  }
488  else {
489  filter_special_loc(src, dest, filter, f1, no_filter());
490  }
491  }
492 
493  template<typename T>
494  static void filter_xy(T&& src, location_set& dest, const terrain_filter& filter, bool with_border)
495  {
496  if (filter.cfg_.has_attribute("x") || filter.cfg_.has_attribute("y")) {
497  std::vector<map_location> xy_vector = filter.fc_->get_disp_context().map().parse_location_range(filter.cfg_["x"], filter.cfg_["y"], with_border);
498  filter_area(src, dest, filter, [&xy_vector](const map_location& loc) { return utils::contains(xy_vector, loc); });
499  }
500  else {
501  filter_area(src, dest, filter, no_filter());
502  }
503  }
504 };
505 //using lambdas with boost transformed gives compile erros on gcc (it works on clang and msvc)
507 {
508  map_location operator()(const config& cfg) const { return map_location(cfg, nullptr); }
510 };
511 void terrain_filter::get_locs_impl(std::set<map_location>& locs, const unit* ref_unit, bool with_border) const
512 {
513  std::unique_ptr<scoped_wml_variable> ref_unit_var;
514  if(ref_unit) {
515  if(fc_->get_disp_context().map().on_board(ref_unit->get_location())) {
516  ref_unit_var.reset(new scoped_xy_unit("teleport_unit", ref_unit->get_location(), fc_->get_disp_context().units()));
517  } else {
518  // Possible TODO: Support recall list units?
519  }
520  }
521 
522  std::set<map_location> match_set;
523 
524  // See if the caller provided an override to with_border
525  with_border = cfg_["include_borders"].to_bool(with_border);
526 
527  if (cfg_.has_attribute("find_in")) {
528 
529  if (const game_data * gd = fc_->get_game_data()) {
530  try
531  {
532  auto ar = gd->get_variable_access_read(cfg_["find_in"]).as_array();
533  terrain_filterimpl::filter_xy(ar | boost::adaptors::transformed(cfg_to_loc()), match_set, *this, with_border);
534  }
535  catch (const invalid_variablename_exception&)
536  {
537  //Do nothing
538  }
539  }
540  }
541  else if (cfg_.has_attribute("x") || cfg_.has_attribute("y")) {
542  std::vector<map_location> xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border);
543  terrain_filterimpl::filter_area(xy_vector, match_set, *this, terrain_filterimpl::no_filter());
544  }
545  else if (cfg_.has_attribute("area")) {
546  const std::set<map_location>& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]);
548  }
549  else if (cfg_.has_attribute("location_id")) {
550  for(const auto& id : utils::split(cfg_["location_id"])) {
552  if(test_loc.valid()) {
553  match_set.insert(test_loc);
554  }
555  }
556  }
557  else if (cfg_["gives_income"].to_bool()) {
558  auto ar = fc_->get_disp_context().map().villages();
559  terrain_filterimpl::filter_xy(ar, match_set, *this, with_border);
560  }
561  else {
562  //consider all locations on the map
563  int bs = fc_->get_disp_context().map().border_size();
564  int w = with_border ? fc_->get_disp_context().map().w() + bs : fc_->get_disp_context().map().w();
565  int h = with_border ? fc_->get_disp_context().map().h() + bs : fc_->get_disp_context().map().h();
566  for (int x = with_border ? 0 - bs : 0; x < w; ++x) {
567  for (int y = with_border ? 0 - bs : 0; y < h; ++y) {
568  match_set.insert(map_location(x, y));
569  }
570  }
571  }
572 
573  //handle location filter
574  if(cfg_.has_child("filter_adjacent_location")) {
575  if(cache_.adjacent_matches == nullptr) {
576  cache_.adjacent_matches.reset(new std::vector<std::set<map_location>>());
577  }
578  const vconfig::child_list& adj_cfgs = cfg_.get_children("filter_adjacent_location");
579  for (unsigned i = 0; i < adj_cfgs.size(); ++i) {
580  std::set<map_location> adj_set;
581  /* GCC-3.3 doesn't like operator[] so use at(), which has the same result */
582  terrain_filter(adj_cfgs.at(i), *this).get_locations(adj_set, with_border);
583  cache_.adjacent_matches->push_back(adj_set);
584  if(i >= max_loop_ && i+1 < adj_cfgs.size()) {
585  ERR_NG << "terrain_filter: loop count greater than " << max_loop_
586  << ", aborting";
587  break;
588  }
589  }
590  }
591  std::set<map_location>::iterator loc_itor = match_set.begin();
592  while(loc_itor != match_set.end()) {
593  if(match_internal(*loc_itor, ref_unit, true)) {
594  ++loc_itor;
595  } else {
596  loc_itor = match_set.erase(loc_itor);
597  }
598  }
599 
600  int ors_left = std::count_if(cfg_.ordered_begin(), cfg_.ordered_end(), [](const auto& val) { return val.first == "or"; });
601 
602  // Handle [and], [or], and [not] with in-order precedence
603  for(const auto& [key, filter] : cfg_.all_ordered()) {
604  //if there are no locations or [or] conditions left, go ahead and return empty
605  if(match_set.empty() && ors_left <= 0) {
606  return;
607  }
608 
609  // Handle [and]
610  if(key == "and") {
611  std::set<map_location> intersect_hexes;
612  terrain_filter(filter, *this).get_locations(intersect_hexes, with_border);
613  std::set<map_location>::iterator intersect_itor = match_set.begin();
614  while(intersect_itor != match_set.end()) {
615  if(intersect_hexes.find(*intersect_itor) == intersect_hexes.end()) {
616  match_set.erase(*intersect_itor++);
617  } else {
618  ++intersect_itor;
619  }
620  }
621  }
622  // Handle [or]
623  else if(key == "or") {
624  std::set<map_location> union_hexes;
625  terrain_filter(filter, *this).get_locations(union_hexes, with_border);
626  //match_set.insert(union_hexes.begin(), union_hexes.end()); //doesn't compile on MSVC
627  std::set<map_location>::iterator insert_itor = union_hexes.begin();
628  while(insert_itor != union_hexes.end()) {
629  match_set.insert(*insert_itor++);
630  }
631  --ors_left;
632  }
633  // Handle [not]
634  else if(key == "not") {
635  std::set<map_location> removal_hexes;
636  terrain_filter(filter, *this).get_locations(removal_hexes, with_border);
637  std::set<map_location>::iterator erase_itor = removal_hexes.begin();
638  while(erase_itor != removal_hexes.end()) {
639  match_set.erase(*erase_itor++);
640  }
641  }
642  }
643  if(match_set.empty()) {
644  return;
645  }
646 
647  //handle radius
648  std::size_t radius = cfg_["radius"].to_size_t(0);
649  if(radius > max_loop_) {
650  ERR_NG << "terrain_filter: radius greater than " << max_loop_
651  << ", restricting";
652  radius = max_loop_;
653  }
654  if(radius > 0) {
655  std::vector<map_location> xy_vector (match_set.begin(), match_set.end());
656  if(cfg_.has_child("filter_radius")) {
657  terrain_filter r_filter(cfg_.child("filter_radius"), *this);
658  get_tiles_radius(fc_->get_disp_context().map(), xy_vector, radius, locs, with_border, r_filter);
659  } else {
660  get_tiles_radius(fc_->get_disp_context().map(), xy_vector, radius, locs, with_border);
661  }
662  } else {
663  locs.insert(match_set.begin(), match_set.end());
664  }
665 }
666 
668 {
669  return cfg_.get_config();
670 }
map_location loc
Definition: move.cpp:172
Variant for storing WML attributes.
bool empty() const
Tests for an attribute that either was never set or was set to "".
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
const team & get_team(int side) const
This getter takes a 1-based side number, not a 0-based team number.
int village_owner(const map_location &loc) const
Given the location of a village, will return the 1-based number of the team that currently owns it,...
virtual const gamemap & map() const =0
virtual const unit_map & units() const =0
virtual const display_context & get_disp_context() const =0
virtual game_lua_kernel * get_lua_kernel() const =0
virtual const tod_manager & get_tod_man() const =0
virtual const game_data * get_game_data() const =0
virtual bool matches(const gamemap_base &m, map_location l) const =0
const unit & ref_
Definition: filter.cpp:362
filter_with_unit(const terrain_filter &filt, const unit &ref)
Definition: filter.cpp:364
const terrain_filter & filt_
Definition: filter.cpp:361
bool operator()(const map_location &loc) const override
Definition: filter.cpp:365
bool run_filter(char const *name, const unit &u)
Runs a script from a unit filter.
int w() const
Effective map width.
Definition: map.hpp:50
int h() const
Effective map height.
Definition: map.hpp:53
map_location special_location(const std::string &id) const
Definition: map.cpp:311
std::vector< map_location > parse_location_range(const std::string &xvals, const std::string &yvals, bool with_border=false) const
Parses ranges of locations into a vector of locations, using this map's dimensions as bounds.
Definition: map.cpp:423
bool on_board_with_border(const map_location &loc) const
Definition: map.cpp:389
int border_size() const
Size of the map border.
Definition: map.hpp:56
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:384
bool is_village(const map_location &loc) const
Definition: map.cpp:66
const std::vector< map_location > & villages() const
Return a list of the locations of villages on the map.
Definition: map.hpp:237
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:98
std::vector< int > get_teams() const
Definition: side_filter.cpp:59
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:74
bool owns_village(const map_location &loc) const
Definition: team.hpp:176
bool shrouded(const map_location &loc) const
Definition: team.cpp:636
bool fogged(const map_location &loc) const
Definition: team.cpp:645
config to_config() const
Definition: filter.cpp:667
bool match_internal(const map_location &loc, const unit *ref_unit, const bool ignore_xy) const
Definition: filter.cpp:97
~terrain_filter()
Default implementation, but defined out-of-line for efficiency reasons.
Definition: filter.cpp:47
bool match_impl(const map_location &loc, const unit *ref_unit) const
Definition: filter.cpp:370
terrain_filter(const vconfig &cfg, const filter_context *fc, const bool flat_tod)
Definition: filter.cpp:51
terrain_filter & operator=(const terrain_filter &other)
Definition: filter.cpp:79
terrain_filter_cache cache_
Definition: filter.hpp:105
const vconfig cfg_
Definition: filter.hpp:87
const std::size_t max_loop_
Definition: filter.hpp:106
const filter_context * fc_
Definition: filter.hpp:88
void get_locs_impl(std::set< map_location > &locs, const unit *ref_unit, bool with_border) const
Definition: filter.cpp:511
static void filter_xy(T &&src, location_set &dest, const terrain_filter &filter, bool with_border)
Definition: filter.cpp:494
static void filter_area(T &&src, location_set &dest, const terrain_filter &filter, const F1 &f1)
Definition: filter.cpp:482
std::set< map_location > location_set
Definition: filter.cpp:446
static void filter_special_loc(T &&src, location_set &dest, const terrain_filter &filter, const F1 &f1, const F2 &f2)
Definition: filter.cpp:464
static void filter_final(T &&src, location_set &dest, const terrain_filter &, const F1 &f1, const F2 &f2, const F3 &f3)
Definition: filter.cpp:454
t_translation::terrain_code number() const
Definition: terrain.hpp:66
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
Definition: tod_manager.hpp:57
time_of_day get_illuminated_time_of_day(const unit_map &units, const gamemap &map, const map_location &loc, int for_turn=0) const
Returns time of day object for the passed turn at a location.
const std::set< map_location > & get_area_by_id(const std::string &id) const
unit_iterator find(std::size_t id)
Definition: map.cpp:302
This class represents a single unit of a specific type.
Definition: unit.hpp:132
Information on a WML variable.
maybe_const_t< config::child_itors, V > as_array() const
If instantiated with vi_policy_const, the lifetime of the returned const attribute_value reference mi...
A variable-expanding proxy for the config class.
Definition: variable.hpp:45
all_children_iterator ordered_begin() const
In-order iteration over all children.
Definition: variable.cpp:481
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition: variable.hpp:99
std::vector< vconfig > child_list
Definition: variable.hpp:78
bool null() const
Definition: variable.hpp:72
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
Definition: variable.cpp:289
const config & get_config() const
Definition: variable.hpp:75
all_children_iterator ordered_end() const
Definition: variable.cpp:486
const vconfig & make_safe() const
instruct the vconfig to make a private copy of its underlying data.
Definition: variable.cpp:164
boost::iterator_range< all_children_iterator > all_ordered() const
Definition: variable.hpp:190
child_list get_children(const std::string &key) const
Definition: variable.cpp:227
bool has_child(const std::string &key) const
Returns whether or not *this has a child whose key is key.
Definition: variable.cpp:316
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:48
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
bool as_bool() const
Returns a boolean state of the variant value.
Definition: variant.cpp:313
Definitions for the interface to Wesnoth Markup Language (WML).
const config * cfg
std::size_t i
Definition: function.cpp:1032
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1431
void get_adjacent_tiles(const map_location &a, utils::span< map_location, 6 > res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:512
Standard logging facilities (interface).
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp >> &ranges)
Definition: math.hpp:87
Game configuration data as global variables.
Definition: build_info.cpp:61
const std::size_t max_loop
The maximum number of hexes on a map and items in an array and also used as maximum in wml loops.
Definition: game_config.cpp:74
std::vector< std::pair< int, int > > default_counts
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
Definition: log.cpp:550
std::function< int(lua_State *)> lua_function
bool terrain_matches(const terrain_code &src, const terrain_code &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
constexpr auto filter
Definition: ranges.hpp:38
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition: general.hpp:87
std::vector< std::pair< int, int > > parse_ranges_unsigned(const std::string &str)
Handles a comma-separated list of inputs to parse_range, in a context that does not expect negative v...
std::vector< std::string > split(const config_attribute_value &val)
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
int w
Definition: pathfind.cpp:188
void get_tiles_radius(const map_location &center, std::size_t radius, std::set< map_location > &result)
Function that will add to result all locations within radius tiles of center (including center itself...
Definition: pathutils.cpp:70
int main(int, char **)
Definition: sdl2.cpp:25
rect src
Non-transparent portion of the surface to compose.
map_location result_type
Definition: filter.cpp:509
map_location operator()(const config &cfg) const
Definition: filter.cpp:508
Encapsulates the map of the game.
Definition: location.hpp:46
static std::vector< direction > parse_directions(const std::string &str)
Parse_directions takes a comma-separated list, and filters out any invalid directions.
Definition: location.cpp:138
static std::vector< direction > all_directions()
Definition: location.cpp:61
bool valid() const
Definition: location.hpp:111
bool matches_range(const std::string &xloc, const std::string &yloc) const
Definition: location.cpp:320
This structure can be used for matching terrain strings.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49
std::unique_ptr< unit_filter > ufilter_
Definition: filter.hpp:102
std::vector< std::pair< terrain_filter, std::map< map_location, bool > > > adjacent_match_cache
Definition: filter.hpp:100
std::unique_ptr< t_translation::ter_match > parsed_terrain
Definition: filter.hpp:94
std::unique_ptr< std::vector< std::set< map_location > > > adjacent_matches
Definition: filter.hpp:97
bool operator()(const map_location &) const
Definition: filter.cpp:450
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:57
std::string id
Definition: time_of_day.hpp:90
int lawful_bonus
The % bonus lawful units receive.
Definition: time_of_day.hpp:83
bool valid() const
Definition: map.hpp:273
#define WRN_NG
Definition: filter.cpp:42
static lg::log_domain log_engine("engine")
#define ERR_NG
Definition: filter.cpp:41
#define ERR_WML
Definition: filter.cpp:45
static lg::log_domain log_wml("wml")
#define e
#define h