The Battle for Wesnoth  1.15.0-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 {
57  return impl_.matches(unit_filter_impl::unit_filter_args{u, u.get_location(), nullptr, fc_, use_flat_tod_});
58 }
59 
60 bool unit_filter::matches(const unit & u, const unit & u2) const {
61  return impl_.matches(unit_filter_impl::unit_filter_args{u, u.get_location(), &u2, fc_, use_flat_tod_});
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.fc->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.fc->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.fc->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 
227 bool unit_filter_compound::matches(const unit_filter_args& args) const
228 {
229  bool res;
230 
231  if(args.loc.valid()) {
232  scoped_xy_unit auto_store("this_unit", args.u.get_location(), args.fc->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.fc->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 
262 bool unit_filter_compound::filter_impl(const unit_filter_args& args) const
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["side"],
438  [](const config::attribute_value& c)
439  {
440  std::vector<int> res;
441  for(const std::string& s : utils::split(c.str())) {
442  try {
443  res.push_back(std::stoi(s));
444  } catch(std::invalid_argument&) {
445  WRN_CF << "ignored invalid side='" << s << "' in filter\n";
446  }
447  }
448  return res;
449  },
450  [](const std::vector<int>& sides, const unit_filter_args& args)
451  {
452  return std::find(sides.begin(), sides.end(), args.u.side()) != sides.end();
453  }
454  );
455 
456  create_attribute(literal["status"],
457  [](const config::attribute_value& c) { return utils::split(c.str()); },
458  [](const std::vector<std::string>& statuses, const unit_filter_args& args)
459  {
460  for(const std::string& status : statuses) {
461  if (args.u.get_state(status)) {
462  return true;
463  }
464  }
465  return false;
466  }
467  );
468 
469  create_attribute(literal["has_weapon"],
470  [](const config::attribute_value& c) { return c.str(); },
471  [](const std::string& weapon, const unit_filter_args& args)
472  {
473 
474  for(const attack_type& a : args.u.attacks()) {
475  if(a.id() == weapon) {
476  return true;
477  }
478  }
479  return false;
480  }
481  );
482 
483  create_attribute(literal["role"],
484  [](const config::attribute_value& c) { return c.str(); },
485  [](const std::string& role, const unit_filter_args& args)
486  {
487  return args.u.get_role() == role;
488  }
489  );
490 
491  create_attribute(literal["alignment"],
492  [](const config::attribute_value& c) { return c.str(); },
493  [](const std::string& alignment, const unit_filter_args& args)
494  {
495  return args.u.alignment().to_string() == alignment;
496  }
497  );
498 
499  create_attribute(literal["ai_special"],
500  [](const config::attribute_value& c) { return c.str(); },
501  [](const std::string& ai_special, const unit_filter_args& args)
502  {
503  return (ai_special == "guardian") == args.u.get_state(unit::STATE_GUARDIAN);
504  }
505  );
506 
507  create_attribute(literal["usage"],
508  [](const config::attribute_value& c) { return utils::split(c.str()); },
509  [](const std::vector<std::string>& usages, const unit_filter_args& args)
510  {
511  for(const std::string& usage : usages) {
512  if(args.u.usage() == usage) {
513  return true;
514  }
515  }
516  return false;
517  }
518  );
519 
520  create_attribute(literal["canrecruit"],
521  [](const config::attribute_value& c) { return c.to_bool(); },
522  [](bool canrecruit, const unit_filter_args& args)
523  {
524  return args.u.can_recruit() == canrecruit;
525  }
526  );
527 
528  create_attribute(literal["recall_cost"],
529  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
530  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
531  {
532  for(auto cost : ranges) {
533  if(cost.first <= args.u.recall_cost() && args.u.recall_cost() <= cost.second) {
534  return true;
535  }
536  }
537  return false;
538  }
539  );
540 
541  create_attribute(literal["level"],
542  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
543  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
544  {
545  for(auto lvl : ranges) {
546  if(lvl.first <= args.u.level() && args.u.level() <= lvl.second) {
547  return true;
548  }
549  }
550  return false;
551  }
552  );
553 
554  create_attribute(literal["defense"],
555  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
556  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
557  {
558  int actual_defense = args.u.defense_modifier(args.fc->get_disp_context().map().get_terrain(args.loc));
559  for(auto def : ranges) {
560  if(def.first <= actual_defense && actual_defense <= def.second) {
561  return true;
562  }
563  }
564  return false;
565  }
566  );
567 
568  create_attribute(literal["movement_cost"],
569  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
570  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
571  {
572  int actual_cost = args.u.movement_cost(args.fc->get_disp_context().map().get_terrain(args.loc));
573  for(auto cost : ranges) {
574  if(cost.first <= actual_cost && actual_cost <= cost.second) {
575  return true;
576  }
577  }
578  return false;
579  }
580  );
581 
582  create_attribute(literal["vision_cost"],
583  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
584  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
585  {
586  int actual_cost = args.u.vision_cost(args.fc->get_disp_context().map().get_terrain(args.loc));
587  for(auto cost : ranges) {
588  if(cost.first <= actual_cost && actual_cost <= cost.second) {
589  return true;
590  }
591  }
592  return false;
593  }
594  );
595 
596  create_attribute(literal["jamming_cost"],
597  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
598  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
599  {
600  int actual_cost = args.u.jamming_cost(args.fc->get_disp_context().map().get_terrain(args.loc));
601  for(auto cost : ranges) {
602  if(cost.first <= actual_cost && actual_cost <= cost.second) {
603  return true;
604  }
605  }
606  return false;
607  }
608  );
609 
610  create_attribute(literal["lua_function"],
611  [](const config::attribute_value& c) { return c.str(); },
612  [](const std::string& lua_function, const unit_filter_args& args)
613  {
614  if (game_lua_kernel * lk = args.fc->get_lua_kernel()) {
615  return lk->run_filter(lua_function.c_str(), args.u);
616  }
617  return true;
618  }
619  );
620 
621  create_attribute(literal["formula"],
622  [](const config::attribute_value& c)
623  {
624  //TODO: catch syntax error.
626  },
627  [](const wfl::formula& form, const unit_filter_args& args)
628  {
629  try {
630  const wfl::unit_callable main(args.loc, args.u);
631  wfl::map_formula_callable callable(main.fake_ptr());
632  if (args.u2) {
633  std::shared_ptr<wfl::unit_callable> secondary(new wfl::unit_callable(*args.u2));
634  callable.add("other", wfl::variant(secondary));
635  // It's not destroyed upon scope exit because the variant holds a reference
636  }
637  if(!form.evaluate(callable).as_bool()) {
638  return false;
639  }
640  return true;
641  } catch(const wfl::formula_error& e) {
642  lg::wml_error() << "Formula error in unit filter: " << e.type << " at " << e.filename << ':' << e.line << ")\n";
643  // Formulae with syntax errors match nothing
644  return false;
645  }
646  }
647  );
648 
649  create_attribute(literal["find_in"],
650  [](const config::attribute_value& c) { return c.str(); },
651  [](const std::string& find_in, const unit_filter_args& args)
652  {
653  // Allow filtering by searching a stored variable of units
654  if (const game_data * gd = args.fc->get_game_data()) {
655  try
656  {
657  for (const config& c : gd->get_variable_access_read(find_in).as_array())
658  {
659  if(c["id"] == args.u.id()) {
660  return true;
661  }
662  }
663  return false;
664  }
665  catch(const invalid_variablename_exception&)
666  {
667  return false;
668  }
669  }
670  return true;
671  }
672  );
673 
674  if (!literal["x"].blank() || !literal["y"].blank()) {
675  children_.emplace_back(new unit_filter_xy(literal["x"], literal["y"]));
676  }
677 
678  for(auto child : cfg.all_ordered()) {
679  CONDITIONAL_TYPE cond;
680  if(cond.parse(child.first)) {
681  cond_children_.emplace_back(std::piecewise_construct_t(), std::make_tuple(cond), std::make_tuple(child.second));
682  }
683  else if (child.first == "filter_wml") {
684  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
685  config fwml = c.get_parsed_config();
686 
687  /* Check if the filter only cares about variables.
688  If so, no need to serialize the whole unit. */
689  config::all_children_itors ci = fwml.all_children_range();
690  if (fwml.all_children_count() == 1 && fwml.attribute_count() == 1 && ci.front().key == "variables") {
691  return args.u.variables().matches(ci.front().cfg);
692  } else {
693  config ucfg;
694  args.u.write(ucfg);
695  return ucfg.matches(fwml);
696  }
697  });
698  }
699  else if (child.first == "filter_vision") {
700  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
701  std::set<int> viewers;
702  side_filter ssf(c, args.fc);
703  std::vector<int> sides = ssf.get_teams();
704  viewers.insert(sides.begin(), sides.end());
705 
706  for (const int viewer : viewers) {
707  bool fogged = args.fc->get_disp_context().get_team(viewer).fogged(args.loc);
708  bool hiding = args.u.invisible(args.loc) && args.fc->get_disp_context().get_team(viewer).is_enemy(args.u.side());
709  bool unit_hidden = fogged || hiding;
710  if (c["visible"].to_bool(true) != unit_hidden) {
711  return true;
712  }
713  }
714  return false;
715  });
716  }
717  else if (child.first == "filter_adjacent") {
718  children_.emplace_back(new unit_filter_adjacent(child.second));
719  }
720  else if (child.first == "filter_location") {
721  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
722  return terrain_filter(c, args.fc, args.use_flat_tod).match(args.loc);
723  });
724  }
725  else if (child.first == "filter_side") {
726  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
727  return side_filter(c, args.fc).match(args.u.side());
728  });
729  }
730  else if (child.first == "has_attack") {
731  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
732  for(const attack_type& a : args.u.attacks()) {
733  if(a.matches_filter(c.get_parsed_config())) {
734  return true;
735  }
736  }
737  return false;
738  });
739  }
740  else {
741  std::stringstream errmsg;
742  errmsg << "encountered a child [" << child.first << "] of a standard unit filter, it is being ignored";
743  DBG_CF << errmsg.str() << std::endl;
744  }
745 
746  }
747  }
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
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 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:1275
virtual const display_context & get_disp_context() const =0
const filter_context * fc_
Definition: filter.hpp:173
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:517
The unit is a guardian - it won&#39;t move unless a target is sighted.
Definition: unit.hpp:752
This class represents a single unit of a specific type.
Definition: unit.hpp:99
int max_matches_
Definition: filter.hpp:176
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:130
vconfig cfg_
Definition: filter.hpp:172
unit_iterator begin()
Definition: map.hpp:405
unit_type_data unit_types
Definition: types.cpp:1452
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp >> &ranges)
Definition: math.hpp:66
bool matches(const unit &u, const map_location &loc) const
Determine if *this matches filter at a specified location.
Definition: filter.hpp:115
bool filter_impl(const unit_filter_args &u) const
Definition: filter.cpp:262
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:123
-file sdl_utils.hpp
Definitions for the interface to Wesnoth Markup Language (WML).
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:175
filter_context * filter_con
Definition: resources.cpp:23
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:174
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:51
virtual const unit_map & units() const =0
const terrain_code NOT
std::array< map_location, 6 > adjacent_loc_array_t
Definition: location.hpp:170
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:90
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
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:91
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:44
bool to_bool(bool def=false) const
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:1184
static int cond(LexState *ls)
Definition: lparser.cpp:1177
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
const config & get_config() const
Definition: variable.hpp:75
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
#define WRN_CF
Definition: filter.cpp:42
bool as_bool() const
Returns a boolean state of the variant value.
Definition: variant.cpp:320
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
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:781
bool empty() const
Definition: config.cpp:886
std::string str(const std::string &fallback="") const
boost::iterator_range< all_children_iterator > all_ordered() const
Definition: variable.hpp:188