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 http://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 "display_context.hpp"
21 #include "game_data.hpp"
22 #include "map/map.hpp"
23 #include "map/location.hpp"
24 #include "scripting/game_lua_kernel.hpp" //Needed for lua kernel
25 #include "side_filter.hpp"
26 #include "team.hpp"
27 #include "terrain/filter.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  bool child_res = filter.second.matches(args);
248 
249  switch (filter.first.v) {
250  case CONDITIONAL_TYPE::AND:
251  res = res && child_res;
252  break;
253  case CONDITIONAL_TYPE::OR:
254  res = res || child_res;
255  break;
257  res = res && !child_res;
258  break;
259  }
260  }
261  return res;
262 }
263 
264 bool unit_filter_compound::filter_impl(const unit_filter_args& args) const
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 
294  {
295  const config& literal = cfg.get_config();
296 
297  //optimisation
298  if(literal.empty()) { return; }
299 
300  create_attribute(literal["name"],
301  [](const config::attribute_value& c) { return c.t_str(); },
302  [](const t_string& str, const unit_filter_args& args) { return str == args.u.name(); }
303  );
304 
305  create_attribute(literal["id"],
306  [](const config::attribute_value& c) { return utils::split(c.str()); },
307  [](const std::vector<std::string>& id_list, const unit_filter_args& args)
308  {
309  return std::find(id_list.begin(), id_list.end(), args.u.id()) != id_list.end();
310  }
311  );
312 
313  create_attribute(literal["type"],
314  [](const config::attribute_value& c) { return utils::split(c.str()); },
315  [](const std::vector<std::string>& types, const unit_filter_args& args)
316  {
317  return std::find(types.begin(), types.end(), args.u.type_id()) != types.end();
318  }
319  );
320 
321  create_attribute(literal["type_adv_tree"],
322  [](const config::attribute_value& c) { return utils::split(c.str()); },
323  [](const std::vector<std::string>& types, const unit_filter_args& args)
324  {
325  std::set<std::string> types_expanded;
326  for(const std::string& type : types) {
327  if(types_expanded.count(type)) {
328  continue;
329  }
330  if(const unit_type* ut = unit_types.find(type)) {
331  const auto& tree = ut->advancement_tree();
332  types_expanded.insert(tree.begin(), tree.end());
333  types_expanded.insert(type);
334  }
335  }
336  return types_expanded.find(args.u.type_id()) != types_expanded.end();
337  }
338  );
339 
340  create_attribute(literal["variation"],
341  [](const config::attribute_value& c) { return utils::split(c.str()); },
342  [](const std::vector<std::string>& types, const unit_filter_args& args)
343  {
344  return std::find(types.begin(), types.end(), args.u.variation()) != types.end();
345  }
346  );
347 
348  create_attribute(literal["has_variation"],
349  [](const config::attribute_value& c) { return utils::split(c.str()); },
350  [](const std::vector<std::string>& types, const unit_filter_args& args)
351  {
352  // If this unit is a variation itself then search in the base unit's variations.
353  const unit_type* const type = args.u.variation().empty() ? &args.u.type() : unit_types.find(args.u.type().base_id());
354  assert(type);
355 
356  for(const std::string& variation_id : types) {
357  if (type->has_variation(variation_id)) {
358  return true;
359  }
360  }
361  return false;
362  }
363  );
364 
365  create_attribute(literal["ability"],
366  [](const config::attribute_value& c) { return utils::split(c.str()); },
367  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
368  {
369  for(const std::string& ability_id : abilities) {
370  if (args.u.has_ability_by_id(ability_id)) {
371  return true;
372  }
373  }
374  return false;
375  }
376  );
377 
378  create_attribute(literal["ability_type"],
379  [](const config::attribute_value& c) { return utils::split(c.str()); },
380  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
381  {
382  for(const std::string& ability : abilities) {
383  if (args.u.has_ability_type(ability)) {
384  return true;
385  }
386  }
387  return false;
388  }
389  );
390 
391  create_attribute(literal["ability_type_active"],
392  [](const config::attribute_value& c) { return utils::split(c.str()); },
393  [](const std::vector<std::string>& abilities, const unit_filter_args& args)
394  {
395  for(const std::string& ability : abilities) {
396  if (!args.u.get_abilities(ability, args.loc).empty()) {
397  return true;
398  }
399  }
400  return false;
401  }
402  );
403 
404  create_attribute(literal["trait"],
405  [](const config::attribute_value& c)
406  {
407  auto res = utils::split(c.str());
408  std::sort(res.begin(), res.end());
409  return res;
410 
411  },
412  [](const std::vector<std::string>& check_traits, const unit_filter_args& args)
413  {
414 
415  std::vector<std::string> have_traits = args.u.get_traits_list();
416  std::vector<std::string> isect;
417  std::sort(have_traits.begin(), have_traits.end());
418  std::set_intersection(check_traits.begin(), check_traits.end(), have_traits.begin(), have_traits.end(), std::back_inserter(isect));
419  return !isect.empty();
420  }
421  );
422 
423  create_attribute(literal["race"],
424  [](const config::attribute_value& c) { return utils::split(c.str()); },
425  [](const std::vector<std::string>& races, const unit_filter_args& args)
426  {
427  return std::find(races.begin(), races.end(), args.u.race()->id()) != races.end();
428  }
429  );
430 
431  create_attribute(literal["gender"],
432  [](const config::attribute_value& c) { return string_gender(c.str()); },
433  [](unit_race::GENDER gender, const unit_filter_args& args)
434  {
435  return gender == args.u.gender();
436  }
437  );
438 
439  create_attribute(literal["side"],
440  [](const config::attribute_value& c)
441  {
442  std::vector<int> res;
443  for(const std::string& s : utils::split(c.str())) {
444  try {
445  res.push_back(std::stoi(s));
446  } catch(std::invalid_argument&) {
447  WRN_CF << "ignored invalid side='" << s << "' in filter\n";
448  }
449  }
450  return res;
451  },
452  [](const std::vector<int>& sides, const unit_filter_args& args)
453  {
454  return std::find(sides.begin(), sides.end(), args.u.side()) != sides.end();
455  }
456  );
457 
458  create_attribute(literal["status"],
459  [](const config::attribute_value& c) { return utils::split(c.str()); },
460  [](const std::vector<std::string>& statuses, const unit_filter_args& args)
461  {
462  for(const std::string& status : statuses) {
463  if (args.u.get_state(status)) {
464  return true;
465  }
466  }
467  return false;
468  }
469  );
470 
471  create_attribute(literal["has_weapon"],
472  [](const config::attribute_value& c) { return c.str(); },
473  [](const std::string& weapon, const unit_filter_args& args)
474  {
475 
476  for(const attack_type& a : args.u.attacks()) {
477  if(a.id() == weapon) {
478  return true;
479  }
480  }
481  return false;
482  }
483  );
484 
485  create_attribute(literal["role"],
486  [](const config::attribute_value& c) { return c.str(); },
487  [](const std::string& role, const unit_filter_args& args)
488  {
489  return args.u.get_role() == role;
490  }
491  );
492 
493  create_attribute(literal["alignment"],
494  [](const config::attribute_value& c) { return c.str(); },
495  [](const std::string& alignment, const unit_filter_args& args)
496  {
497  return args.u.alignment().to_string() == alignment;
498  }
499  );
500 
501  create_attribute(literal["ai_special"],
502  [](const config::attribute_value& c) { return c.str(); },
503  [](const std::string& ai_special, const unit_filter_args& args)
504  {
505  return (ai_special == "guardian") == args.u.get_state(unit::STATE_GUARDIAN);
506  }
507  );
508 
509  create_attribute(literal["usage"],
510  [](const config::attribute_value& c) { return utils::split(c.str()); },
511  [](const std::vector<std::string>& usages, const unit_filter_args& args)
512  {
513  for(const std::string& usage : usages) {
514  if(args.u.usage() == usage) {
515  return true;
516  }
517  }
518  return false;
519  }
520  );
521 
522  create_attribute(literal["canrecruit"],
523  [](const config::attribute_value& c) { return c.to_bool(); },
524  [](bool canrecruit, const unit_filter_args& args)
525  {
526  return args.u.can_recruit() == canrecruit;
527  }
528  );
529 
530  create_attribute(literal["recall_cost"],
531  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
532  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
533  {
534  for(auto cost : ranges) {
535  if(cost.first <= args.u.recall_cost() && args.u.recall_cost() <= cost.second) {
536  return true;
537  }
538  }
539  return false;
540  }
541  );
542 
543  create_attribute(literal["level"],
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 lvl : ranges) {
548  if(lvl.first <= args.u.level() && args.u.level() <= lvl.second) {
549  return true;
550  }
551  }
552  return false;
553  }
554  );
555 
556  create_attribute(literal["defense"],
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  int actual_defense = args.u.defense_modifier(args.fc->get_disp_context().map().get_terrain(args.loc));
561  for(auto def : ranges) {
562  if(def.first <= actual_defense && actual_defense <= def.second) {
563  return true;
564  }
565  }
566  return false;
567  }
568  );
569 
570  create_attribute(literal["movement_cost"],
571  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
572  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
573  {
574  int actual_cost = args.u.movement_cost(args.fc->get_disp_context().map().get_terrain(args.loc));
575  for(auto cost : ranges) {
576  if(cost.first <= actual_cost && actual_cost <= cost.second) {
577  return true;
578  }
579  }
580  return false;
581  }
582  );
583 
584  create_attribute(literal["vision_cost"],
585  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
586  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
587  {
588  int actual_cost = args.u.vision_cost(args.fc->get_disp_context().map().get_terrain(args.loc));
589  for(auto cost : ranges) {
590  if(cost.first <= actual_cost && actual_cost <= cost.second) {
591  return true;
592  }
593  }
594  return false;
595  }
596  );
597 
598  create_attribute(literal["jamming_cost"],
599  [](const config::attribute_value& c) { return utils::parse_ranges(c.str()); },
600  [](const std::vector<std::pair<int,int>>& ranges, const unit_filter_args& args)
601  {
602  int actual_cost = args.u.jamming_cost(args.fc->get_disp_context().map().get_terrain(args.loc));
603  for(auto cost : ranges) {
604  if(cost.first <= actual_cost && actual_cost <= cost.second) {
605  return true;
606  }
607  }
608  return false;
609  }
610  );
611 
612  create_attribute(literal["lua_function"],
613  [](const config::attribute_value& c) { return c.str(); },
614  [](const std::string& lua_function, const unit_filter_args& args)
615  {
616  if (game_lua_kernel * lk = args.fc->get_lua_kernel()) {
617  return lk->run_filter(lua_function.c_str(), args.u);
618  }
619  return true;
620  }
621  );
622 
623  create_attribute(literal["formula"],
624  [](const config::attribute_value& c)
625  {
626  //TODO: catch syntax error.
628  },
629  [](const wfl::formula& form, const unit_filter_args& args)
630  {
631  try {
632  const wfl::unit_callable main(args.loc, args.u);
633  wfl::map_formula_callable callable(main.fake_ptr());
634  if (args.u2) {
635  std::shared_ptr<wfl::unit_callable> secondary(new wfl::unit_callable(*args.u2));
636  callable.add("other", wfl::variant(secondary));
637  // It's not destroyed upon scope exit because the variant holds a reference
638  }
639  if(!form.evaluate(callable).as_bool()) {
640  return false;
641  }
642  return true;
643  } catch(const wfl::formula_error& e) {
644  lg::wml_error() << "Formula error in unit filter: " << e.type << " at " << e.filename << ':' << e.line << ")\n";
645  // Formulae with syntax errors match nothing
646  return false;
647  }
648  }
649  );
650 
651  create_attribute(literal["find_in"],
652  [](const config::attribute_value& c) { return c.str(); },
653  [](const std::string& find_in, const unit_filter_args& args)
654  {
655  // Allow filtering by searching a stored variable of units
656  if (const game_data * gd = args.fc->get_game_data()) {
657  try
658  {
659  for (const config& c : gd->get_variable_access_read(find_in).as_array())
660  {
661  if(c["id"] == args.u.id()) {
662  return true;
663  }
664  }
665  return false;
666  }
667  catch(const invalid_variablename_exception&)
668  {
669  return false;
670  }
671  }
672  return true;
673  }
674  );
675 
676  if (!literal["x"].blank() || !literal["y"].blank()) {
677  children_.emplace_back(new unit_filter_xy(literal["x"], literal["y"]));
678  }
679 
680  for(auto child : cfg.all_ordered()) {
681  CONDITIONAL_TYPE cond;
682  if(cond.parse(child.first)) {
683  cond_children_.emplace_back(std::piecewise_construct_t(), std::make_tuple(cond), std::make_tuple(child.second));
684  }
685  else if (child.first == "filter_wml") {
686  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
687  config fwml = c.get_parsed_config();
688 
689  /* Check if the filter only cares about variables.
690  If so, no need to serialize the whole unit. */
691  config::all_children_itors ci = fwml.all_children_range();
692  if (fwml.all_children_count() == 1 && fwml.attribute_count() == 1 && ci.front().key == "variables") {
693  return args.u.variables().matches(ci.front().cfg);
694  } else {
695  config ucfg;
696  args.u.write(ucfg);
697  return ucfg.matches(fwml);
698  }
699  });
700  }
701  else if (child.first == "filter_vision") {
702  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
703  std::set<int> viewers;
704  side_filter ssf(c, args.fc);
705  std::vector<int> sides = ssf.get_teams();
706  viewers.insert(sides.begin(), sides.end());
707 
708  for (const int viewer : viewers) {
709  bool fogged = args.fc->get_disp_context().get_team(viewer).fogged(args.loc);
710  bool hiding = args.u.invisible(args.loc) && args.fc->get_disp_context().get_team(viewer).is_enemy(args.u.side());
711  bool unit_hidden = fogged || hiding;
712  if (c["visible"].to_bool(true) != unit_hidden) {
713  return true;
714  }
715  }
716  return false;
717  });
718  }
719  else if (child.first == "filter_adjacent") {
720  children_.emplace_back(new unit_filter_adjacent(child.second));
721  }
722  else if (child.first == "filter_location") {
723  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
724  return terrain_filter(c, args.fc, args.use_flat_tod).match(args.loc);
725  });
726  }
727  else if (child.first == "filter_side") {
728  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
729  return side_filter(c, args.fc).match(args.u.side());
730  });
731  }
732  else if (child.first == "has_attack") {
733  create_child(child.second, [](const vconfig& c, const unit_filter_args& args) {
734  for(const attack_type& a : args.u.attacks()) {
735  if(a.matches_filter(c.get_parsed_config())) {
736  return true;
737  }
738  }
739  return false;
740  });
741  }
742  else {
743  std::stringstream errmsg;
744  errmsg << "encountered a child [" << child.first << "] of a standard unit filter, it is being ignored";
745  DBG_CF << errmsg.str() << std::endl;
746  }
747 
748  }
749  }
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:172
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:747
This class represents a single unit of a specific type.
Definition: unit.hpp:99
int max_matches_
Definition: filter.hpp:175
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:129
vconfig cfg_
Definition: filter.hpp:171
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:114
bool filter_impl(const unit_filter_args &u) const
Definition: filter.cpp:264
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:174
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:173
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
Definition: race.cpp:149
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:89
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:138
std::vector< std::pair< CONDITIONAL_TYPE, unit_filter_compound > > cond_children_
Definition: filter.hpp:90
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: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
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1174
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: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:781
bool empty() const
Definition: config.cpp:837
std::string str(const std::string &fallback="") const
boost::iterator_range< all_children_iterator > all_ordered() const
Definition: variable.hpp:188