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