The Battle for Wesnoth  1.15.12+dev
filter.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "units/filter.hpp"
16 
17 #include "log.hpp"
18 
19 #include "display.hpp"
20 #include "display_context.hpp"
21 #include "config.hpp"
22 #include "game_data.hpp"
23 #include "map/map.hpp"
24 #include "map/location.hpp"
25 #include "scripting/game_lua_kernel.hpp" //Needed for lua kernel
26 #include "side_filter.hpp"
27 #include "team.hpp"
28 #include "terrain/filter.hpp"
29 #include "tod_manager.hpp"
30 #include "units/unit.hpp"
32 #include "units/types.hpp"
33 #include "variable.hpp" // needed for vconfig, scoped unit
34 #include "formula/callable_objects.hpp"
35 #include "formula/formula.hpp"
37 #include "formula/string_utils.hpp"
38 #include "resources.hpp"
39 
40 static lg::log_domain log_config("config");
41 #define ERR_CF LOG_STREAM(err, log_config)
42 #define WRN_CF LOG_STREAM(warn, log_config)
43 #define DBG_CF LOG_STREAM(debug, log_config)
44 
45 using namespace unit_filter_impl;
46 
48  : cfg_(cfg)
49  , fc_(resources::filter_con)
50  , use_flat_tod_(false)
51  , impl_(cfg_)
52  , max_matches_(-1)
53 {
54 }
55 
56 bool unit_filter::matches(const unit& u) const {
58 }
59 
60 bool unit_filter::matches(const unit & u, const unit & u2) const {
62 }
63 
64 std::vector<const unit *> unit_filter::all_matches_on_map(const map_location* loc, const unit* other_unit) const
65 {
66  std::vector<const unit *> ret;
67  int max_matches = max_matches_;
68 
69  for (const unit & u : fc_->get_disp_context().units()) {
70  if (impl_.matches(unit_filter_impl::unit_filter_args{u, loc ? *loc : u.get_location(), other_unit, fc_, use_flat_tod_})) {
71  if(max_matches == 0) {
72  return ret;
73  }
74  --max_matches;
75  ret.push_back(&u);
76  }
77  }
78  return ret;
79 }
80 
82  const unit_map & units = fc_->get_disp_context().units();
83  for(unit_map::const_iterator u = units.begin(); u != units.end(); ++u) {
84  if (matches(*u, u->get_location())) {
85  return u.get_shared_ptr();
86  }
87  }
88  return unit_const_ptr();
89 }
90 
91 namespace {
92 
93 struct unit_filter_xy : public unit_filter_base
94 {
95  unit_filter_xy(const std::string& x, const std::string& y) : x_(x), y_(y) {}
96 
97  virtual bool matches(const unit_filter_args& args) const override
98  {
101 
102  if(x.empty() && y.empty()) {
103  return false;
104  }
105  else if(x == "recall" && y == "recall") {
106  return !args.context().get_disp_context().map().on_board(args.loc);
107  }
108  else {
109  return args.loc.matches_range(x, y);
110  }
111  }
112 
113  const std::string x_;
114  const std::string y_;
115 };
116 
117 struct unit_filter_adjacent : public unit_filter_base
118 {
119  unit_filter_adjacent(const vconfig& cfg)
120  : child_(cfg)
121  , cfg_(cfg)
122  {
123  }
124 
125  virtual bool matches(const unit_filter_args& args) const override
126  {
127  const unit_map& units = args.context().get_disp_context().units();
128  const auto adjacent = get_adjacent_tiles(args.loc);
129  int match_count=0;
130 
131  config::attribute_value i_adjacent = cfg_["adjacent"];
132  std::vector<map_location::DIRECTION> dirs;
133  if (i_adjacent.empty()) {
135  } else {
136  dirs = map_location::parse_directions(i_adjacent);
137  }
138  for (map_location::DIRECTION dir : dirs) {
139  unit_map::const_iterator unit_itor = units.find(adjacent[dir]);
140  if (unit_itor == units.end() || !child_.matches(unit_filter_args{*unit_itor, unit_itor->get_location(), &args.u, args.fc, args.use_flat_tod} )) {
141  continue;
142  }
143  auto is_enemy = cfg_["is_enemy"];
144  if (!is_enemy.empty() && is_enemy.to_bool() != args.context().get_disp_context().get_team(args.u.side()).is_enemy(unit_itor->side())) {
145  continue;
146  }
147  ++match_count;
148  }
149 
150  static std::vector<std::pair<int,int>> default_counts = utils::parse_ranges("1-6");
151  config::attribute_value i_count = cfg_["count"];
152  return in_ranges(match_count, !i_count.blank() ? utils::parse_ranges(i_count) : default_counts);
153  }
154 
155  const unit_filter_compound child_;
156  const vconfig cfg_;
157 };
158 
159 
160 template<typename F>
161 struct unit_filter_child_literal : public unit_filter_base
162 {
163  unit_filter_child_literal(const vconfig& v, const F& f) : v_(v) , f_(f) {}
164  virtual bool matches(const unit_filter_args& args) const override
165  {
166  return f_(v_, args);
167  }
168  vconfig v_;
169  F f_;
170 };
171 
172 template<typename T, typename F>
173 struct unit_filter_attribute_parsed : public unit_filter_base
174 {
175  unit_filter_attribute_parsed(T&& v, F&& f) : v_(std::move(v)), f_(std::move(f)) {}
176  virtual bool matches(const unit_filter_args& args) const override
177  {
178  return f_(v_, args);
179  }
180  T v_;
181  F f_;
182 };
183 
184 template<typename C, typename F>
185 struct unit_filter_attribute_literal : public unit_filter_base
186 {
187  unit_filter_attribute_literal(std::string&& v, C&& c, F&& f) : v_(std::move(v)), c_(std::move(c)), f_(std::move(f)) {}
188  virtual bool matches(const unit_filter_args& args) const override
189  {
192  return f_(c_(v), args);
193  }
194  std::string v_;
195  C c_;
196  F f_;
197 };
198 
199 class contains_dollar_visitor
200 #ifdef USING_BOOST_VARIANT
201  : public boost::static_visitor<bool>
202 #endif
203 {
204 public:
205  contains_dollar_visitor() {}
206 
207 
208  template<typename T>
209  bool operator()(const T&) const { return false; }
210 
211  bool operator()(const t_string&) const { return true; }
212 
213  bool operator()(const std::string& s) const
214  {
215  return s.find('$') != std::string::npos;
216  }
217 };
218 
219 }
220 
221 
222 unit_filter_compound::unit_filter_compound(vconfig cfg)
223  : children_()
224  , cond_children_()
225 {
226  fill(cfg);
227 }
228 
230 {
231  bool res;
232 
233  if(args.loc.valid()) {
234  scoped_xy_unit auto_store("this_unit", args.u.get_location(), args.context().get_disp_context().units());
235  if (args.u2) {
236  const map_location& loc2 = args.u2->get_location();
237  scoped_xy_unit u2_auto_store("other_unit", loc2, args.context().get_disp_context().units());
238  res = filter_impl(args);
239  } else {
240  res = filter_impl(args);
241  }
242  } else {
243  // If loc is invalid, then this is a recall list unit (already been scoped)
244  res = filter_impl(args);
245  }
246 
247  // Handle [and], [or], and [not] with in-order precedence
248  for(const auto & filter : cond_children_) {
249  switch (filter.first.v) {
250  case CONDITIONAL_TYPE::AND:
251  res = res && filter.second.matches(args);
252  break;
253  case CONDITIONAL_TYPE::OR:
254  res = res || filter.second.matches(args);
255  break;
257  res = res && !filter.second.matches(args);
258  break;
259  }
260  }
261  return res;
262 }
263 
265 {
266  for(const auto & filter : children_) {
267  if (!filter->matches(args)) {
268  return false;
269  }
270  }
271  return true;
272 }
273 
274 template<typename F>
276 {
277  children_.emplace_back(new unit_filter_child_literal<F>(c, func));
278 }
279 
280 template<typename C, typename F>
282 {
283  if(v.blank()) {
284  }
285  else if(v.apply_visitor(contains_dollar_visitor())) {
286  children_.emplace_back(new unit_filter_attribute_literal<C, F>(std::move(v.str()), std::move(conv), std::move(func)));
287  }
288  else {
289  children_.emplace_back(new unit_filter_attribute_parsed<decltype(conv(v)), F>(std::move(conv(v)), std::move(func)));
290  }
291 }
292 
293 namespace {
294 
295  struct ability_match
296  {
297  std::string tag_name;
298  const config* cfg;
299  };
300 
301  void get_ability_children_id(std::vector<ability_match>& id_result,
302  const config& parent, const std::string& id) {
303  for (const config::any_child &sp : parent.all_children_range())
304  {
305  if(sp.cfg["id"] == id) {
306  ability_match special = { sp.key, &sp.cfg };
307  id_result.push_back(special);
308  }
309  }
310  }
311 }
312 
314  {
315  const config& literal = cfg.get_config();
316 
317  //optimisation
318  if(literal.empty()) { return; }
319 
320  create_attribute(literal["name"],
321  [](const config::attribute_value& c) { return c.t_str(); },
322  [](const t_string& str, const unit_filter_args& args) { return str == args.u.name(); }
323  );
324 
325  create_attribute(literal["id"],
326  [](const config::attribute_value& c) { return utils::split(c.str()); },
327  [](const std::vector<std::string>& id_list, const unit_filter_args& args)
328  {
329  return std::find(id_list.begin(), id_list.end(), args.u.id()) != id_list.end();
330  }
331  );
332 
333  create_attribute(literal["type"],
334  [](const config::attribute_value& c) { return utils::split(c.str()); },
335  [](const std::vector<std::string>& types, const unit_filter_args& args)
336  {
337  return std::find(types.begin(), types.end(), args.u.type_id()) != types.end();
338  }
339  );
340 
341  create_attribute(literal["type_adv_tree"],
342  [](const config::attribute_value& c) { return utils::split(c.str()); },
343  [](const std::vector<std::string>& types, const unit_filter_args& args)
344  {
345  std::set<std::string> types_expanded;
346  for(const std::string& type : types) {
347  if(types_expanded.count(type)) {
348  continue;
349  }
350  if(const unit_type* ut = unit_types.find(type)) {
351  const auto& tree = ut->advancement_tree();
352  types_expanded.insert(tree.begin(), tree.end());
353  types_expanded.insert(type);
354  }
355  }
356  return types_expanded.find(args.u.type_id()) != types_expanded.end();
357  }
358  );
359 
360  create_attribute(literal["variation"],
361  [](const config::attribute_value& c) { return utils::split(c.str()); },
362  [](const std::vector<std::string>& types, const unit_filter_args& args)
363  {
364  return std::find(types.begin(), types.end(), args.u.variation()) != types.end();
365  }
366  );
367 
368  create_attribute(literal["has_variation"],
369  [](const config::attribute_value& c) { return utils::split(c.str()); },
370  [](const std::vector<std::string>& types, const unit_filter_args& args)
371  {
372  // If this unit is a variation itself then search in the base unit's variations.
373  const unit_type* const type = args.u.variation().empty() ? &args.u.type() : unit_types.find(args.u.type().parent_id());
374  assert(type);
375 
376  for(const std::string& variation_id : types) {
377  if (type->has_variation(variation_id)) {
378  return true;
379  }
380  }
381  return false;
382  }
383  );
384 
385  create_attribute(literal["ability"],
386  [](const config::attribute_value& c) { return utils::split(c.str()); },
387  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
388  {
389  for(const std::string& ability_id : abilities) {
390  if (args.u.has_ability_by_id(ability_id)) {
391  return true;
392  }
393  }
394  return false;
395  }
396  );
397 
398  create_attribute(literal["ability_type"],
399  [](const config::attribute_value& c) { return utils::split(c.str()); },
400  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
401  {
402  for(const std::string& ability : abilities) {
403  if (args.u.has_ability_type(ability)) {
404  return true;
405  }
406  }
407  return false;
408  }
409  );
410 
411  create_attribute(literal["ability_id_active"],
412  [](const config::attribute_value& c) { return utils::split(c.str()); },
413  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
414  {
415  assert(display::get_singleton());
416  const unit_map& units = display::get_singleton()->get_units();
417  for(const std::string& ability : abilities) {
418  std::vector<ability_match> ability_id_matches_self;
419  get_ability_children_id(ability_id_matches_self, args.u.abilities(), ability);
420  for(const ability_match& entry : ability_id_matches_self) {
421  if (args.u.get_self_ability_bool(*entry.cfg, entry.tag_name, args.loc)) {
422  return true;
423  }
424  }
425 
426  const auto adjacent = get_adjacent_tiles(args.loc);
427  for(unsigned i = 0; i < adjacent.size(); ++i) {
428  const unit_map::const_iterator it = units.find(adjacent[i]);
429  if (it == units.end() || it->incapacitated())
430  continue;
431  if (&*it == (args.u.shared_from_this()).get())
432  continue;
433 
434  std::vector<ability_match> ability_id_matches_adj;
435  get_ability_children_id(ability_id_matches_adj, it->abilities(), ability);
436  for(const ability_match& entry : ability_id_matches_adj) {
437  if (args.u.get_adj_ability_bool(*entry.cfg, entry.tag_name,i, args.loc, *it)) {
438  return true;
439  }
440  }
441  }
442  }
443  return false;
444  }
445  );
446 
447  create_attribute(literal["ability_type_active"],
448  [](const config::attribute_value& c) { return utils::split(c.str()); },
449  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
450  {
451  for(const std::string& ability : abilities) {
452  if (!args.u.get_abilities(ability, args.loc).empty()) {
453  return true;
454  }
455  }
456  return false;
457  }
458  );
459 
460  create_attribute(literal["trait"],
461  [](const config::attribute_value& c)
462  {
463  auto res = utils::split(c.str());
464  std::sort(res.begin(), res.end());
465  return res;
466 
467  },
468  [](const std::vector<std::string>& check_traits, const unit_filter_args& args)
469  {
470 
471  std::vector<std::string> have_traits = args.u.get_traits_list();
472  std::vector<std::string> isect;
473  std::sort(have_traits.begin(), have_traits.end());
474  std::set_intersection(check_traits.begin(), check_traits.end(), have_traits.begin(), have_traits.end(), std::back_inserter(isect));
475  return !isect.empty();
476  }
477  );
478 
479  create_attribute(literal["race"],
480  [](const config::attribute_value& c) { return utils::split(c.str()); },
481  [](const std::vector<std::string>& races, const unit_filter_args& args)
482  {
483  return std::find(races.begin(), races.end(), args.u.race()->id()) != races.end();
484  }
485  );
486 
487  create_attribute(literal["gender"],
488  [](const config::attribute_value& c) { return string_gender(c.str()); },
489  [](unit_race::GENDER gender, const unit_filter_args& args)
490  {
491  return gender == args.u.gender();
492  }
493  );
494 
495  create_attribute(literal["upkeep"],
497  {
498  try {
500  } catch(std::invalid_argument&) {
501  return unit::upkeep_full();
502  }
503  },
504  [](unit::upkeep_t upkeep, const unit_filter_args& args)
505  {
506  return args.u.upkeep() == utils::visit(unit::upkeep_value_visitor{args.u}, upkeep);
507  }
508  );
509 
510  create_attribute(literal["side"],
511  [](const config::attribute_value& c)
512  {
513  std::vector<int> res;
514  for(const std::string& s : utils::split(c.str())) {
515  try {
516  res.push_back(std::stoi(s));
517  } catch(std::invalid_argument&) {
518  WRN_CF << "ignored invalid side='" << s << "' in filter\n";
519  }
520  }
521  return res;
522  },
523  [](const std::vector<int>& sides, const unit_filter_args& args)
524  {
525  return std::find(sides.begin(), sides.end(), args.u.side()) != sides.end();
526  }
527  );
528 
529  create_attribute(literal["status"],
530  [](const config::attribute_value& c) { return utils::split(c.str()); },
531  [](const std::vector<std::string>& statuses, const unit_filter_args& args)
532  {
533  for(const std::string& status : statuses) {
534  if (args.u.get_state(status)) {
535  return true;
536  }
537  }
538  return false;
539  }
540  );
541 
542  create_attribute(literal["has_weapon"],
543  [](const config::attribute_value& c) { return c.str(); },
544  [](const std::string& weapon, const unit_filter_args& args)
545  {
546 
547  for(const attack_type& a : args.u.attacks()) {
548  if(a.id() == weapon) {
549  return true;
550  }
551  }
552  return false;
553  }
554  );
555 
556  create_attribute(literal["role"],
557  [](const config::attribute_value& c) { return c.str(); },
558  [](const std::string& role, const unit_filter_args& args)
559  {
560  return args.u.get_role() == role;
561  }
562  );
563 
564  create_attribute(literal["alignment"],
565  [](const config::attribute_value& c) { return c.str(); },
566  [](const std::string& alignment, const unit_filter_args& args)
567  {
568  return args.u.alignment().to_string() == alignment;
569  }
570  );
571 
572  create_attribute(literal["ai_special"],
573  [](const config::attribute_value& c) { return c.str(); },
574  [](const std::string& ai_special, const unit_filter_args& args)
575  {
576  return (ai_special == "guardian") == args.u.get_state(unit::STATE_GUARDIAN);
577  }
578  );
579 
580  create_attribute(literal["usage"],
581  [](const config::attribute_value& c) { return utils::split(c.str()); },
582  [](const std::vector<std::string>& usages, const unit_filter_args& args)
583  {
584  for(const std::string& usage : usages) {
585  if(args.u.usage() == usage) {
586  return true;
587  }
588  }
589  return false;
590  }
591  );
592 
593  create_attribute(literal["canrecruit"],
594  [](const config::attribute_value& c) { return c.to_bool(); },
595  [](bool canrecruit, const unit_filter_args& args)
596  {
597  return args.u.can_recruit() == canrecruit;
598  }
599  );
600 
601  create_attribute(literal["recall_cost"],
602  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
603  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
604  {
605  for(auto cost : ranges) {
606  if(cost.first <= args.u.recall_cost() && args.u.recall_cost() <= cost.second) {
607  return true;
608  }
609  }
610  return false;
611  }
612  );
613 
614  create_attribute(literal["level"],
615  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
616  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
617  {
618  for(auto lvl : ranges) {
619  if(lvl.first <= args.u.level() && args.u.level() <= lvl.second) {
620  return true;
621  }
622  }
623  return false;
624  }
625  );
626 
627  create_attribute(literal["defense"],
628  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
629  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
630  {
631  int actual_defense = args.u.defense_modifier(args.context().get_disp_context().map().get_terrain(args.loc));
632  for(auto def : ranges) {
633  if(def.first <= actual_defense && actual_defense <= def.second) {
634  return true;
635  }
636  }
637  return false;
638  }
639  );
640 
641  create_attribute(literal["movement_cost"],
642  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
643  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
644  {
645  int actual_cost = args.u.movement_cost(args.context().get_disp_context().map().get_terrain(args.loc));
646  for(auto cost : ranges) {
647  if(cost.first <= actual_cost && actual_cost <= cost.second) {
648  return true;
649  }
650  }
651  return false;
652  }
653  );
654 
655  create_attribute(literal["vision_cost"],
656  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
657  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
658  {
659  int actual_cost = args.u.vision_cost(args.context().get_disp_context().map().get_terrain(args.loc));
660  for(auto cost : ranges) {
661  if(cost.first <= actual_cost && actual_cost <= cost.second) {
662  return true;
663  }
664  }
665  return false;
666  }
667  );
668 
669  create_attribute(literal["jamming_cost"],
670  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
671  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
672  {
673  int actual_cost = args.u.jamming_cost(args.context().get_disp_context().map().get_terrain(args.loc));
674  for(auto cost : ranges) {
675  if(cost.first <= actual_cost && actual_cost <= cost.second) {
676  return true;
677  }
678  }
679  return false;
680  }
681  );
682 
683  create_attribute(literal["lua_function"],
684  [](const config::attribute_value& c) { return c.str(); },
685  [](const std::string& lua_function, const unit_filter_args& args)
686  {
687  if (game_lua_kernel * lk = args.context().get_lua_kernel()) {
688  return lk->run_filter(lua_function.c_str(), args.u);
689  }
690  return true;
691  }
692  );
693 
694  create_attribute(literal["formula"],
695  [](const config::attribute_value& c)
696  {
697  //TODO: catch syntax error.
699  },
700  [](const wfl::formula& form, const unit_filter_args& args)
701  {
702  try {
703  const wfl::unit_callable main(args.loc, args.u);
704  wfl::map_formula_callable callable(main.fake_ptr());
705  if (args.u2) {
706  std::shared_ptr<wfl::unit_callable> secondary(new wfl::unit_callable(*args.u2));
707  callable.add("other", wfl::variant(secondary));
708  // It's not destroyed upon scope exit because the variant holds a reference
709  }
710  if(!form.evaluate(callable).as_bool()) {
711  return false;
712  }
713  return true;
714  } catch(const wfl::formula_error& e) {
715  lg::wml_error() << "Formula error in unit filter: " << e.type << " at " << e.filename << ':' << e.line << ")\n";
716  // Formulae with syntax errors match nothing
717  return false;
718  }
719  }
720  );
721 
722  create_attribute(literal["find_in"],
723  [](const config::attribute_value& c) { return c.str(); },
724  [](const std::string& find_in, const unit_filter_args& args)
725  {
726  // Allow filtering by searching a stored variable of units
727  if (const game_data * gd = args.context().get_game_data()) {
728  try
729  {
730  for (const config& c : gd->get_variable_access_read(find_in).as_array())
731  {
732  if(c["id"] == args.u.id()) {
733  return true;
734  }
735  }
736  return false;
737  }
738  catch(const invalid_variablename_exception&)
739  {
740  return false;
741  }
742  }
743  return true;
744  }
745  );
746 
747  if (!literal["x"].blank() || !literal["y"].blank()) {
748  children_.emplace_back(new unit_filter_xy(literal["x"], literal["y"]));
749  }
750 
751  for(auto child : cfg.all_ordered()) {
752  CONDITIONAL_TYPE cond;
753  if(cond.parse(child.first)) {
754  cond_children_.emplace_back(std::piecewise_construct_t(), std::tuple(cond), std::tuple(child.second));
755  }
756  else if (child.first == "filter_wml") {
757  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
758  config fwml = c.get_parsed_config();
759 
760  /* Check if the filter only cares about variables.
761  If so, no need to serialize the whole unit. */
762  config::all_children_itors ci = fwml.all_children_range();
763  if (fwml.all_children_count() == 1 && fwml.attribute_count() == 1 && ci.front().key == "variables") {
764  return args.u.variables().matches(ci.front().cfg);
765  } else {
766  config ucfg;
767  args.u.write(ucfg);
768  return ucfg.matches(fwml);
769  }
770  });
771  }
772  else if (child.first == "filter_vision") {
773  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
774  std::set<int> viewers;
775  side_filter ssf(c, args.fc);
776  std::vector<int> sides = ssf.get_teams();
777  viewers.insert(sides.begin(), sides.end());
778 
779  for (const int viewer : viewers) {
780  bool fogged = args.context().get_disp_context().get_team(viewer).fogged(args.loc);
781  // Check is_enemy() before invisible() to prevent infinite recursion in [abilities][hides][filter_self][filter_vision]
782  bool hiding = args.context().get_disp_context().get_team(viewer).is_enemy(args.u.side()) && args.u.invisible(args.loc);
783  bool unit_hidden = fogged || hiding;
784  if (c["visible"].to_bool(true) != unit_hidden) {
785  return true;
786  }
787  }
788  return false;
789  });
790  }
791  else if (child.first == "filter_adjacent") {
792  children_.emplace_back(new unit_filter_adjacent(child.second));
793  }
794  else if (child.first == "filter_location") {
795  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
796  return terrain_filter(c, args.fc, args.use_flat_tod).match(args.loc);
797  });
798  }
799  else if (child.first == "filter_side") {
800  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
801  return side_filter(c, args.fc).match(args.u.side());
802  });
803  }
804  else if (child.first == "has_attack") {
805  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
806  for(const attack_type& a : args.u.attacks()) {
807  if(a.matches_filter(c.get_parsed_config())) {
808  return true;
809  }
810  }
811  return false;
812  });
813  }
814  else {
815  std::stringstream errmsg;
816  errmsg << "encountered a child [" << child.first << "] of a standard unit filter, it is being ignored";
817  DBG_CF << errmsg.str() << std::endl;
818  }
819 
820  }
821  }
static lg::log_domain log_config("config")
std::function< int(lua_State *)> lua_function
bool empty() const
Tests for an attribute that either was never set or was set to "".
unit_iterator end()
Definition: map.hpp:428
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:91
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:953
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with &#39;$&#39; in the string &#39;str&#39; with the equivalent ...
const team & get_team(int side) const
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1228
virtual const display_context & get_disp_context() const =0
const filter_context * fc_
Definition: filter.hpp:191
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:474
The unit cannot be healed.
Definition: unit.hpp:859
This class represents a single unit of a specific type.
Definition: unit.hpp:120
int max_matches_
Definition: filter.hpp:194
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:39
#define DBG_CF
Definition: filter.cpp:43
Variant for storing WML attributes.
std::string filename
Definition: formula.hpp:107
#define a
void create_child(const vconfig &c, F func)
Definition: filter.cpp:275
bool operator()(const unit &u, const map_location &loc) const
Definition: filter.hpp:148
vconfig cfg_
Definition: filter.hpp:190
unit_iterator begin()
Definition: map.hpp:418
const unit_map & get_units() const
Definition: display.hpp:124
unit_type_data unit_types
Definition: types.cpp:1447
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp >> &ranges)
Definition: math.hpp:86
bool matches(const unit &u, const map_location &loc) const
Determine if *this matches filter at a specified location.
Definition: filter.hpp:131
bool filter_impl(const unit_filter_args &u) const
Definition: filter.cpp:264
const filter_context & context() const
Definition: filter.hpp:70
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:124
Definitions for the interface to Wesnoth Markup Language (WML).
virtual const gamemap & map() const =0
int main(int argc, char **argv)
Definition: SDLMain.mm:101
unit_filter(vconfig cfg)
Definition: filter.cpp:47
A single unit type that the player may recruit.
Definition: types.hpp:44
game_data * gamedata
Definition: resources.cpp:22
utils::variant< upkeep_full, upkeep_loyal, int > upkeep_t
Definition: unit.hpp:1128
std::shared_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:26
static T & get_lua_kernel(lua_State *L)
std::vector< std::pair< int, int > > parse_ranges(const std::string &str)
std::vector< std::pair< int, int > > default_counts
unit_filter_impl::unit_filter_compound impl_
Definition: filter.hpp:193
filter_context * filter_con
Definition: resources.cpp:23
bool valid() const
Definition: location.hpp:88
std::string type
Definition: formula.hpp:105
bool blank() const
Tests for an attribute that was never set.
bool use_flat_tod_
Definition: filter.hpp:192
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
Definition: race.cpp:143
static const std::vector< DIRECTION > & default_dirs()
Default list of directions.
Definition: location.cpp:52
map_display and display: classes which take care of displaying the map and game-data on the screen...
virtual const unit_map & units() const =0
const terrain_code NOT
const filter_context * fc
Definition: filter.hpp:67
Encapsulates the map of the game.
Definition: location.hpp:37
unit_iterator find(std::size_t id)
Definition: map.cpp:309
unit_const_ptr first_match_on_map() const
Definition: filter.cpp:81
std::vector< std::shared_ptr< unit_filter_base > > children_
Definition: filter.hpp:104
std::size_t i
Definition: function.cpp:940
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:288
formula_callable_ptr fake_ptr()
Definition: callable.hpp:41
Visitor helper class to fetch the appropriate upkeep value.
Definition: unit.hpp:1131
static map_location::DIRECTION s
pump_impl & impl_
Definition: pump.cpp:134
std::vector< std::pair< CONDITIONAL_TYPE, unit_filter_compound > > cond_children_
Definition: filter.hpp:105
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:380
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:39
bool to_bool(bool def=false) const
bool matches_range(const std::string &xloc, const std::string &yloc) const
Definition: location.cpp:317
static int sort(lua_State *L)
Definition: ltablib.cpp:397
void create_attribute(const config::attribute_value c, C conv, F func)
Definition: filter.cpp:281
std::vector< const unit * > all_matches_on_map(const map_location *loc=nullptr, const unit *other_unit=nullptr) const
Definition: filter.cpp:64
#define f
std::vector< std::string > split(const config_attribute_value &val)
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1348
static int cond(LexState *ls)
Definition: lparser.cpp:1394
A variable-expanding proxy for the config class.
Definition: variable.hpp:44
const config & get_config() const
Definition: variable.hpp:75
Standard logging facilities (interface).
auto apply_visitor(const V &visitor) const
Visitor support: Applies a visitor to the underlying variant.
Container associating units to locations.
Definition: map.hpp:97
#define e
int side() const
The side this unit belongs to.
Definition: unit.hpp:333
#define WRN_CF
Definition: filter.cpp:42
Visitor helper class to parse the upkeep value from a config.
Definition: unit.hpp:1181
bool as_bool() const
Returns a boolean state of the variant value.
Definition: variant.cpp:316
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
mock_char c
virtual bool matches(const unit_filter_args &u) const override
Definition: filter.cpp:229
bool has_variation(const std::string &variation_id) const
Definition: types.cpp:726
bool empty() const
Definition: config.cpp:916
std::string str(const std::string &fallback="") const
boost::iterator_range< all_children_iterator > all_ordered() const
Definition: variable.hpp:190