The Battle for Wesnoth  1.15.2+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 "config.hpp"
20 #include "game_data.hpp"
21 #include "map/map.hpp"
22 #include "map/location.hpp"
23 #include "scripting/game_lua_kernel.hpp" //Needed for lua kernel
24 #include "side_filter.hpp"
25 #include "team.hpp"
26 #include "terrain/filter.hpp"
27 #include "tod_manager.hpp"
28 #include "units/unit.hpp"
30 #include "units/types.hpp"
31 #include "variable.hpp" // needed for vconfig, scoped unit
32 #include "formula/callable_objects.hpp"
33 #include "formula/formula.hpp"
35 #include "formula/string_utils.hpp"
36 #include "resources.hpp"
37 
38 #include <boost/optional.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  adjacent_loc_array_t adjacent;
129  get_adjacent_tiles(args.loc, adjacent.data());
130  int match_count=0;
131 
132  config::attribute_value i_adjacent = cfg_["adjacent"];
133  std::vector<map_location::DIRECTION> dirs;
134  if (i_adjacent.empty()) {
136  } else {
137  dirs = map_location::parse_directions(i_adjacent);
138  }
139  for (map_location::DIRECTION dir : dirs) {
140  unit_map::const_iterator unit_itor = units.find(adjacent[dir]);
141  if (unit_itor == units.end() || !child_.matches(unit_filter_args{*unit_itor, unit_itor->get_location(), &args.u, args.fc, args.use_flat_tod} )) {
142  continue;
143  }
144  auto is_enemy = cfg_["is_enemy"];
145  if (!is_enemy.empty() && is_enemy.to_bool() != args.context().get_disp_context().get_team(args.u.side()).is_enemy(unit_itor->side())) {
146  continue;
147  }
148  ++match_count;
149  }
150 
151  static std::vector<std::pair<int,int>> default_counts = utils::parse_ranges("1-6");
152  config::attribute_value i_count = cfg_["count"];
153  return in_ranges(match_count, !i_count.blank() ? utils::parse_ranges(i_count) : default_counts);
154  }
155 
156  const unit_filter_compound child_;
157  const vconfig cfg_;
158 };
159 
160 
161 template<typename F>
162 struct unit_filter_child_literal : public unit_filter_base
163 {
164  unit_filter_child_literal(const vconfig& v, const F& f) : v_(v) , f_(f) {}
165  virtual bool matches(const unit_filter_args& args) const override
166  {
167  return f_(v_, args);
168  }
169  vconfig v_;
170  F f_;
171 };
172 
173 template<typename T, typename F>
174 struct unit_filter_attribute_parsed : public unit_filter_base
175 {
176  unit_filter_attribute_parsed(T&& v, F&& f) : v_(std::move(v)), f_(std::move(f)) {}
177  virtual bool matches(const unit_filter_args& args) const override
178  {
179  return f_(v_, args);
180  }
181  T v_;
182  F f_;
183 };
184 
185 template<typename C, typename F>
186 struct unit_filter_attribute_literal : public unit_filter_base
187 {
188  unit_filter_attribute_literal(std::string&& v, C&& c, F&& f) : v_(std::move(v)), c_(std::move(c)), f_(std::move(f)) {}
189  virtual bool matches(const unit_filter_args& args) const override
190  {
193  return f_(c_(v), args);
194  }
195  std::string v_;
196  C c_;
197  F f_;
198 };
199 
200 class contains_dollar_visitor : public boost::static_visitor<bool>
201 {
202 public:
203  contains_dollar_visitor() {}
204 
205 
206  template<typename T>
207  bool operator()(const T&) const { return false; }
208 
209  bool operator()(const t_string&) const { return true; }
210 
211  bool operator()(const std::string& s) const
212  {
213  return s.find('$') != std::string::npos;
214  }
215 };
216 
217 }
218 
219 
220 unit_filter_compound::unit_filter_compound(vconfig cfg)
221  : children_()
222  , cond_children_()
223 {
224  fill(cfg);
225 }
226 
228 {
229  bool res;
230 
231  if(args.loc.valid()) {
232  scoped_xy_unit auto_store("this_unit", args.u.get_location(), args.context().get_disp_context().units());
233  if (args.u2) {
234  const map_location& loc2 = args.u2->get_location();
235  scoped_xy_unit u2_auto_store("other_unit", loc2, args.context().get_disp_context().units());
236  res = filter_impl(args);
237  } else {
238  res = filter_impl(args);
239  }
240  } else {
241  // If loc is invalid, then this is a recall list unit (already been scoped)
242  res = filter_impl(args);
243  }
244 
245  // Handle [and], [or], and [not] with in-order precedence
246  for(const auto & filter : cond_children_) {
247  switch (filter.first.v) {
248  case CONDITIONAL_TYPE::AND:
249  res = res && filter.second.matches(args);
250  break;
251  case CONDITIONAL_TYPE::OR:
252  res = res || filter.second.matches(args);
253  break;
255  res = res && !filter.second.matches(args);
256  break;
257  }
258  }
259  return res;
260 }
261 
263 {
264  for(const auto & filter : children_) {
265  if (!filter->matches(args)) {
266  return false;
267  }
268  }
269  return true;
270 }
271 
272 template<typename F>
274 {
275  children_.emplace_back(new unit_filter_child_literal<F>(c, func));
276 }
277 
278 template<typename C, typename F>
280 {
281  if(v.blank()) {
282  }
283  else if(v.apply_visitor(contains_dollar_visitor())) {
284  children_.emplace_back(new unit_filter_attribute_literal<C, F>(std::move(v.str()), std::move(conv), std::move(func)));
285  }
286  else {
287  children_.emplace_back(new unit_filter_attribute_parsed<decltype(conv(v)), F>(std::move(conv(v)), std::move(func)));
288  }
289 }
290 
292  {
293  const config& literal = cfg.get_config();
294 
295  //optimisation
296  if(literal.empty()) { return; }
297 
298  create_attribute(literal["name"],
299  [](const config::attribute_value& c) { return c.t_str(); },
300  [](const t_string& str, const unit_filter_args& args) { return str == args.u.name(); }
301  );
302 
303  create_attribute(literal["id"],
304  [](const config::attribute_value& c) { return utils::split(c.str()); },
305  [](const std::vector<std::string>& id_list, const unit_filter_args& args)
306  {
307  return std::find(id_list.begin(), id_list.end(), args.u.id()) != id_list.end();
308  }
309  );
310 
311  create_attribute(literal["type"],
312  [](const config::attribute_value& c) { return utils::split(c.str()); },
313  [](const std::vector<std::string>& types, const unit_filter_args& args)
314  {
315  return std::find(types.begin(), types.end(), args.u.type_id()) != types.end();
316  }
317  );
318 
319  create_attribute(literal["type_adv_tree"],
320  [](const config::attribute_value& c) { return utils::split(c.str()); },
321  [](const std::vector<std::string>& types, const unit_filter_args& args)
322  {
323  std::set<std::string> types_expanded;
324  for(const std::string& type : types) {
325  if(types_expanded.count(type)) {
326  continue;
327  }
328  if(const unit_type* ut = unit_types.find(type)) {
329  const auto& tree = ut->advancement_tree();
330  types_expanded.insert(tree.begin(), tree.end());
331  types_expanded.insert(type);
332  }
333  }
334  return types_expanded.find(args.u.type_id()) != types_expanded.end();
335  }
336  );
337 
338  create_attribute(literal["variation"],
339  [](const config::attribute_value& c) { return utils::split(c.str()); },
340  [](const std::vector<std::string>& types, const unit_filter_args& args)
341  {
342  return std::find(types.begin(), types.end(), args.u.variation()) != types.end();
343  }
344  );
345 
346  create_attribute(literal["has_variation"],
347  [](const config::attribute_value& c) { return utils::split(c.str()); },
348  [](const std::vector<std::string>& types, const unit_filter_args& args)
349  {
350  // If this unit is a variation itself then search in the base unit's variations.
351  const unit_type* const type = args.u.variation().empty() ? &args.u.type() : unit_types.find(args.u.type().base_id());
352  assert(type);
353 
354  for(const std::string& variation_id : types) {
355  if (type->has_variation(variation_id)) {
356  return true;
357  }
358  }
359  return false;
360  }
361  );
362 
363  create_attribute(literal["ability"],
364  [](const config::attribute_value& c) { return utils::split(c.str()); },
365  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
366  {
367  for(const std::string& ability_id : abilities) {
368  if (args.u.has_ability_by_id(ability_id)) {
369  return true;
370  }
371  }
372  return false;
373  }
374  );
375 
376  create_attribute(literal["ability_type"],
377  [](const config::attribute_value& c) { return utils::split(c.str()); },
378  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
379  {
380  for(const std::string& ability : abilities) {
381  if (args.u.has_ability_type(ability)) {
382  return true;
383  }
384  }
385  return false;
386  }
387  );
388 
389  create_attribute(literal["ability_type_active"],
390  [](const config::attribute_value& c) { return utils::split(c.str()); },
391  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
392  {
393  for(const std::string& ability : abilities) {
394  if (!args.u.get_abilities(ability, args.loc).empty()) {
395  return true;
396  }
397  }
398  return false;
399  }
400  );
401 
402  create_attribute(literal["trait"],
403  [](const config::attribute_value& c)
404  {
405  auto res = utils::split(c.str());
406  std::sort(res.begin(), res.end());
407  return res;
408 
409  },
410  [](const std::vector<std::string>& check_traits, const unit_filter_args& args)
411  {
412 
413  std::vector<std::string> have_traits = args.u.get_traits_list();
414  std::vector<std::string> isect;
415  std::sort(have_traits.begin(), have_traits.end());
416  std::set_intersection(check_traits.begin(), check_traits.end(), have_traits.begin(), have_traits.end(), std::back_inserter(isect));
417  return !isect.empty();
418  }
419  );
420 
421  create_attribute(literal["race"],
422  [](const config::attribute_value& c) { return utils::split(c.str()); },
423  [](const std::vector<std::string>& races, const unit_filter_args& args)
424  {
425  return std::find(races.begin(), races.end(), args.u.race()->id()) != races.end();
426  }
427  );
428 
429  create_attribute(literal["gender"],
430  [](const config::attribute_value& c) { return string_gender(c.str()); },
431  [](unit_race::GENDER gender, const unit_filter_args& args)
432  {
433  return gender == args.u.gender();
434  }
435  );
436 
437  create_attribute(literal["upkeep"],
439  {
440  try {
442  } catch(std::invalid_argument&) {
443  return unit::upkeep_full();
444  }
445  },
446  [](unit::upkeep_t upkeep, const unit_filter_args& args)
447  {
448  return args.u.upkeep() == boost::apply_visitor(unit::upkeep_value_visitor(args.u), upkeep);
449  }
450  );
451 
452  create_attribute(literal["side"],
453  [](const config::attribute_value& c)
454  {
455  std::vector<int> res;
456  for(const std::string& s : utils::split(c.str())) {
457  try {
458  res.push_back(std::stoi(s));
459  } catch(std::invalid_argument&) {
460  WRN_CF << "ignored invalid side='" << s << "' in filter\n";
461  }
462  }
463  return res;
464  },
465  [](const std::vector<int>& sides, const unit_filter_args& args)
466  {
467  return std::find(sides.begin(), sides.end(), args.u.side()) != sides.end();
468  }
469  );
470 
471  create_attribute(literal["status"],
472  [](const config::attribute_value& c) { return utils::split(c.str()); },
473  [](const std::vector<std::string>& statuses, const unit_filter_args& args)
474  {
475  for(const std::string& status : statuses) {
476  if (args.u.get_state(status)) {
477  return true;
478  }
479  }
480  return false;
481  }
482  );
483 
484  create_attribute(literal["has_weapon"],
485  [](const config::attribute_value& c) { return c.str(); },
486  [](const std::string& weapon, const unit_filter_args& args)
487  {
488 
489  for(const attack_type& a : args.u.attacks()) {
490  if(a.id() == weapon) {
491  return true;
492  }
493  }
494  return false;
495  }
496  );
497 
498  create_attribute(literal["role"],
499  [](const config::attribute_value& c) { return c.str(); },
500  [](const std::string& role, const unit_filter_args& args)
501  {
502  return args.u.get_role() == role;
503  }
504  );
505 
506  create_attribute(literal["alignment"],
507  [](const config::attribute_value& c) { return c.str(); },
508  [](const std::string& alignment, const unit_filter_args& args)
509  {
510  return args.u.alignment().to_string() == alignment;
511  }
512  );
513 
514  create_attribute(literal["ai_special"],
515  [](const config::attribute_value& c) { return c.str(); },
516  [](const std::string& ai_special, const unit_filter_args& args)
517  {
518  return (ai_special == "guardian") == args.u.get_state(unit::STATE_GUARDIAN);
519  }
520  );
521 
522  create_attribute(literal["usage"],
523  [](const config::attribute_value& c) { return utils::split(c.str()); },
524  [](const std::vector<std::string>& usages, const unit_filter_args& args)
525  {
526  for(const std::string& usage : usages) {
527  if(args.u.usage() == usage) {
528  return true;
529  }
530  }
531  return false;
532  }
533  );
534 
535  create_attribute(literal["canrecruit"],
536  [](const config::attribute_value& c) { return c.to_bool(); },
537  [](bool canrecruit, const unit_filter_args& args)
538  {
539  return args.u.can_recruit() == canrecruit;
540  }
541  );
542 
543  create_attribute(literal["recall_cost"],
544  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
545  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
546  {
547  for(auto cost : ranges) {
548  if(cost.first <= args.u.recall_cost() && args.u.recall_cost() <= cost.second) {
549  return true;
550  }
551  }
552  return false;
553  }
554  );
555 
556  create_attribute(literal["level"],
557  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
558  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
559  {
560  for(auto lvl : ranges) {
561  if(lvl.first <= args.u.level() && args.u.level() <= lvl.second) {
562  return true;
563  }
564  }
565  return false;
566  }
567  );
568 
569  create_attribute(literal["defense"],
570  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
571  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
572  {
573  int actual_defense = args.u.defense_modifier(args.context().get_disp_context().map().get_terrain(args.loc));
574  for(auto def : ranges) {
575  if(def.first <= actual_defense && actual_defense <= def.second) {
576  return true;
577  }
578  }
579  return false;
580  }
581  );
582 
583  create_attribute(literal["movement_cost"],
584  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
585  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
586  {
587  int actual_cost = args.u.movement_cost(args.context().get_disp_context().map().get_terrain(args.loc));
588  for(auto cost : ranges) {
589  if(cost.first <= actual_cost && actual_cost <= cost.second) {
590  return true;
591  }
592  }
593  return false;
594  }
595  );
596 
597  create_attribute(literal["vision_cost"],
598  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
599  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
600  {
601  int actual_cost = args.u.vision_cost(args.context().get_disp_context().map().get_terrain(args.loc));
602  for(auto cost : ranges) {
603  if(cost.first <= actual_cost && actual_cost <= cost.second) {
604  return true;
605  }
606  }
607  return false;
608  }
609  );
610 
611  create_attribute(literal["jamming_cost"],
612  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
613  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
614  {
615  int actual_cost = args.u.jamming_cost(args.context().get_disp_context().map().get_terrain(args.loc));
616  for(auto cost : ranges) {
617  if(cost.first <= actual_cost && actual_cost <= cost.second) {
618  return true;
619  }
620  }
621  return false;
622  }
623  );
624 
625  create_attribute(literal["lua_function"],
626  [](const config::attribute_value& c) { return c.str(); },
627  [](const std::string& lua_function, const unit_filter_args& args)
628  {
629  if (game_lua_kernel * lk = args.context().get_lua_kernel()) {
630  return lk->run_filter(lua_function.c_str(), args.u);
631  }
632  return true;
633  }
634  );
635 
636  create_attribute(literal["formula"],
637  [](const config::attribute_value& c)
638  {
639  //TODO: catch syntax error.
641  },
642  [](const wfl::formula& form, const unit_filter_args& args)
643  {
644  try {
645  const wfl::unit_callable main(args.loc, args.u);
646  wfl::map_formula_callable callable(main.fake_ptr());
647  if (args.u2) {
648  std::shared_ptr<wfl::unit_callable> secondary(new wfl::unit_callable(*args.u2));
649  callable.add("other", wfl::variant(secondary));
650  // It's not destroyed upon scope exit because the variant holds a reference
651  }
652  if(!form.evaluate(callable).as_bool()) {
653  return false;
654  }
655  return true;
656  } catch(const wfl::formula_error& e) {
657  lg::wml_error() << "Formula error in unit filter: " << e.type << " at " << e.filename << ':' << e.line << ")\n";
658  // Formulae with syntax errors match nothing
659  return false;
660  }
661  }
662  );
663 
664  create_attribute(literal["find_in"],
665  [](const config::attribute_value& c) { return c.str(); },
666  [](const std::string& find_in, const unit_filter_args& args)
667  {
668  // Allow filtering by searching a stored variable of units
669  if (const game_data * gd = args.context().get_game_data()) {
670  try
671  {
672  for (const config& c : gd->get_variable_access_read(find_in).as_array())
673  {
674  if(c["id"] == args.u.id()) {
675  return true;
676  }
677  }
678  return false;
679  }
680  catch(const invalid_variablename_exception&)
681  {
682  return false;
683  }
684  }
685  return true;
686  }
687  );
688 
689  if (!literal["x"].blank() || !literal["y"].blank()) {
690  children_.emplace_back(new unit_filter_xy(literal["x"], literal["y"]));
691  }
692 
693  for(auto child : cfg.all_ordered()) {
694  CONDITIONAL_TYPE cond;
695  if(cond.parse(child.first)) {
696  cond_children_.emplace_back(std::piecewise_construct_t(), std::make_tuple(cond), std::make_tuple(child.second));
697  }
698  else if (child.first == "filter_wml") {
699  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
700  config fwml = c.get_parsed_config();
701 
702  /* Check if the filter only cares about variables.
703  If so, no need to serialize the whole unit. */
704  config::all_children_itors ci = fwml.all_children_range();
705  if (fwml.all_children_count() == 1 && fwml.attribute_count() == 1 && ci.front().key == "variables") {
706  return args.u.variables().matches(ci.front().cfg);
707  } else {
708  config ucfg;
709  args.u.write(ucfg);
710  return ucfg.matches(fwml);
711  }
712  });
713  }
714  else if (child.first == "filter_vision") {
715  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
716  std::set<int> viewers;
717  side_filter ssf(c, args.fc);
718  std::vector<int> sides = ssf.get_teams();
719  viewers.insert(sides.begin(), sides.end());
720 
721  for (const int viewer : viewers) {
722  bool fogged = args.context().get_disp_context().get_team(viewer).fogged(args.loc);
723  // Check is_enemy() before invisible() to prevent infinite recursion in [abilities][hides][filter_self][filter_vision]
724  bool hiding = args.context().get_disp_context().get_team(viewer).is_enemy(args.u.side()) && args.u.invisible(args.loc);
725  bool unit_hidden = fogged || hiding;
726  if (c["visible"].to_bool(true) != unit_hidden) {
727  return true;
728  }
729  }
730  return false;
731  });
732  }
733  else if (child.first == "filter_adjacent") {
734  children_.emplace_back(new unit_filter_adjacent(child.second));
735  }
736  else if (child.first == "filter_location") {
737  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
738  return terrain_filter(c, args.fc, args.use_flat_tod).match(args.loc);
739  });
740  }
741  else if (child.first == "filter_side") {
742  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
743  return side_filter(c, args.fc).match(args.u.side());
744  });
745  }
746  else if (child.first == "has_attack") {
747  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
748  for(const attack_type& a : args.u.attacks()) {
749  if(a.matches_filter(c.get_parsed_config())) {
750  return true;
751  }
752  }
753  return false;
754  });
755  }
756  else {
757  std::stringstream errmsg;
758  errmsg << "encountered a child [" << child.first << "] of a standard unit filter, it is being ignored";
759  DBG_CF << errmsg.str() << std::endl;
760  }
761 
762  }
763  }
static lg::log_domain log_config("config")
boost::intrusive_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:30
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:415
V::result_t apply_visitor(typename V::param_t state, T &&... args)
Helper function to apply the result of a specified visitor to a variable_info object.
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:1271
virtual const display_context & get_disp_context() const =0
const filter_context * fc_
Definition: filter.hpp:187
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 is a guardian - it won&#39;t move unless a target is sighted.
Definition: unit.hpp:837
This class represents a single unit of a specific type.
Definition: unit.hpp:99
int max_matches_
Definition: filter.hpp:190
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:273
bool operator()(const unit &u, const map_location &loc) const
Definition: filter.hpp:144
vconfig cfg_
Definition: filter.hpp:186
unit_iterator begin()
Definition: map.hpp:405
unit_type_data unit_types
Definition: types.cpp:1529
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp >> &ranges)
Definition: math.hpp:66
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:377
bool matches(const unit &u, const map_location &loc) const
Determine if *this matches filter at a specified location.
Definition: filter.hpp:129
bool filter_impl(const unit_filter_args &u) const
Definition: filter.cpp:262
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
-file sdl_utils.hpp
Definitions for the interface to Wesnoth Markup Language (WML).
virtual const gamemap & map() const =0
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
unit_filter(vconfig cfg)
Definition: filter.cpp:47
A single unit type that the player may recruit.
Definition: types.hpp:42
game_data * gamedata
Definition: resources.cpp:22
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:189
filter_context * filter_con
Definition: resources.cpp:23
bool valid() const
Definition: location.hpp:93
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:188
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
Definition: race.cpp:141
static const std::vector< DIRECTION > & default_dirs()
Default list of directions.
Definition: location.cpp:52
virtual const unit_map & units() const =0
const terrain_code NOT
std::array< map_location, 6 > adjacent_loc_array_t
Definition: location.hpp:170
const filter_context * fc
Definition: filter.hpp:67
Encapsulates the map of the game.
Definition: location.hpp:42
unit_iterator find(std::size_t id)
Definition: map.cpp:311
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::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:269
formula_callable_ptr fake_ptr()
Definition: callable.hpp:41
Visitor helper class to fetch the appropriate upkeep value.
Definition: unit.hpp:1103
int main()
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
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:44
bool to_bool(bool def=false) const
bool matches_range(const std::string &xloc, const std::string &yloc) const
Definition: location.cpp:317
boost::variant< upkeep_full, upkeep_loyal, int > upkeep_t
Definition: unit.hpp:1146
static int sort(lua_State *L)
Definition: ltablib.cpp:411
void create_attribute(const config::attribute_value c, C conv, F func)
Definition: filter.cpp:279
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
bool find(E event, F functor)
Tests whether an event handler is available.
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1313
static int cond(LexState *ls)
Definition: lparser.cpp:1177
A variable-expanding proxy for the config class.
Definition: variable.hpp:44
const config & get_config() const
Definition: variable.hpp:82
Standard logging facilities (interface).
V::result_type apply_visitor(const V &visitor) const
Applies a visitor to the underlying variant.
Container associating units to locations.
Definition: map.hpp:99
#define e
int side() const
The side this unit belongs to.
Definition: unit.hpp:304
#define WRN_CF
Definition: filter.cpp:42
Visitor helper class to parse the upkeep value from a config.
Definition: unit.hpp:1149
bool as_bool() const
Returns a boolean state of the variant value.
Definition: variant.cpp:314
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
mock_char c
virtual bool matches(const unit_filter_args &u) const override
Definition: filter.cpp:227
bool has_variation(const std::string &variation_id) const
Definition: types.cpp:784
bool empty() const
Definition: config.cpp:884
std::string str(const std::string &fallback="") const
boost::iterator_range< all_children_iterator > all_ordered() const
Definition: variable.hpp:197