35 #include "formula/callable_objects.hpp" 42 #define ERR_CF LOG_STREAM(err, log_config) 43 #define WRN_CF LOG_STREAM(warn, log_config) 44 #define DBG_CF LOG_STREAM(debug, log_config) 47 #define ERR_WML LOG_STREAM(err, log_wml) 54 , use_flat_tod_(false)
70 std::vector<const unit *> ret;
75 if(max_matches == 0) {
88 if (
matches(*u, u->get_location())) {
89 return u.get_shared_ptr();
99 unit_filter_xy(
const std::string& x,
const std::string& y) : x_(x), y_(y) {}
106 if(x.empty() && y.empty()) {
109 else if(x ==
"recall" && y ==
"recall") {
117 const std::string x_;
118 const std::string y_;
123 unit_filter_adjacent(
const vconfig& cfg)
136 std::vector<map_location::DIRECTION> dirs;
137 if (i_adjacent.
empty()) {
147 auto is_enemy =
cfg_[
"is_enemy"];
167 unit_filter_child_literal(
const vconfig& v,
const F&
f) : v_(v) , f_(f) {}
176 template<
typename T,
typename F>
179 unit_filter_attribute_parsed(T&& v, F&&
f) : v_(std::move(v)), f_(std::move(
f)) {}
188 template<
typename C,
typename F>
191 unit_filter_attribute_literal(std::string&& v, C&&
c, F&&
f) : v_(std::move(v)), c_(std::move(
c)), f_(std::move(
f)) {}
196 return f_(c_(v), args);
203 class contains_dollar_visitor
204 #ifdef USING_BOOST_VARIANT
205 :
public boost::static_visitor<bool>
209 contains_dollar_visitor() {}
213 bool operator()(
const T&)
const {
return false; }
219 return s.find(
'$') != std::string::npos;
226 unit_filter_compound::unit_filter_compound(
vconfig cfg)
253 switch (filter.first) {
254 case conditional_type::type::filter_and:
255 res = res && filter.second.matches(args);
257 case conditional_type::type::filter_or:
258 res = res || filter.second.matches(args);
260 case conditional_type::type::filter_not:
261 res = res && !filter.second.matches(args);
271 if (!filter->matches(args)) {
281 children_.emplace_back(
new unit_filter_child_literal<F>(c, func));
284 template<
typename C,
typename F>
290 children_.emplace_back(
new unit_filter_attribute_literal<C, F>(std::move(v.
str()), std::move(conv), std::move(func)));
293 children_.emplace_back(
new unit_filter_attribute_parsed<decltype(conv(v)), F>(std::move(conv(v)), std::move(func)));
301 std::string tag_name;
305 void get_ability_children_id(std::vector<ability_match>& id_result,
306 const config& parent,
const std::string&
id) {
309 if(
sp.cfg[
"id"] ==
id) {
310 ability_match special = {
sp.key, &
sp.cfg };
311 id_result.push_back(special);
322 if(literal.
empty()) {
return; }
333 return std::find(id_list.begin(), id_list.end(), args.u.id()) != id_list.end();
341 return std::find(types.begin(), types.end(), args.u.type_id()) != types.end();
349 std::set<std::string> types_expanded;
350 for(
const std::string&
type : types) {
351 if(types_expanded.count(
type)) {
355 const auto& tree = ut->advancement_tree();
356 types_expanded.insert(tree.begin(), tree.end());
357 types_expanded.insert(
type);
360 return types_expanded.find(args.u.type_id()) != types_expanded.end();
368 return std::find(types.begin(), types.end(), args.u.variation()) != types.end();
380 for(
const std::string& variation_id : types) {
393 for(
const std::string& ability_id : abilities) {
394 if (args.u.has_ability_by_id(ability_id)) {
406 for(
const std::string& ability : abilities) {
407 if (args.u.has_ability_type(ability)) {
421 for(
const std::string& ability : abilities) {
422 std::vector<ability_match> ability_id_matches_self;
423 get_ability_children_id(ability_id_matches_self, args.u.abilities(), ability);
424 for(
const ability_match& entry : ability_id_matches_self) {
425 if (args.u.get_self_ability_bool(*entry.cfg, entry.tag_name, args.loc)) {
431 for(
unsigned i = 0;
i < adjacent.size(); ++
i) {
433 if (it == units.
end() || it->incapacitated())
435 if (&*it == (args.u.shared_from_this()).
get())
438 std::vector<ability_match> ability_id_matches_adj;
439 get_ability_children_id(ability_id_matches_adj, it->abilities(), ability);
440 for(
const ability_match& entry : ability_id_matches_adj) {
441 if (args.u.get_adj_ability_bool(*entry.cfg, entry.tag_name,i, args.loc, *it)) {
455 for(
const std::string& ability : abilities) {
456 if (!args.u.get_abilities(ability, args.loc).empty()) {
468 std::sort(res.begin(), res.end());
472 [](
const std::vector<std::string>& check_traits,
const unit_filter_args& args)
475 std::vector<std::string> have_traits = args.u.get_traits_list();
476 std::vector<std::string> isect;
477 std::sort(have_traits.begin(), have_traits.end());
478 std::set_intersection(check_traits.begin(), check_traits.end(), have_traits.begin(), have_traits.end(), std::back_inserter(isect));
479 return !isect.empty();
487 return std::find(races.begin(), races.end(), args.u.race()->id()) != races.end();
495 return gender == args.u.gender();
504 }
catch(std::invalid_argument&) {
517 std::vector<int> res;
520 res.push_back(std::stoi(
s));
521 }
catch(std::invalid_argument&) {
522 WRN_CF <<
"ignored invalid side='" <<
s <<
"' in filter";
529 return std::find(sides.begin(), sides.end(), args.u.side()) != sides.end();
537 for(
const std::string& status : statuses) {
538 if (args.u.get_state(status)) {
552 if(
a.id() == weapon) {
564 return args.u.get_role() == role;
588 for(
const std::string& usage : usages) {
589 if(args.u.usage() == usage) {
601 return args.u.can_recruit() == canrecruit;
607 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
609 for(
auto cost : ranges) {
610 if(cost.first <= args.u.recall_cost() && args.u.recall_cost() <= cost.second) {
620 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
622 for(
auto lvl : ranges) {
623 if(lvl.first <= args.u.level() && args.u.level() <= lvl.second) {
633 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
635 int actual_defense = args.u.defense_modifier(args.context().get_disp_context().map().get_terrain(args.loc));
636 for(
auto def : ranges) {
637 if(def.first <= actual_defense && actual_defense <= def.second) {
647 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
649 int actual_cost = args.u.movement_cost(args.context().get_disp_context().map().get_terrain(args.loc));
650 for(
auto cost : ranges) {
651 if(cost.first <= actual_cost && actual_cost <= cost.second) {
661 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
663 int actual_cost = args.u.vision_cost(args.context().get_disp_context().map().get_terrain(args.loc));
664 for(
auto cost : ranges) {
665 if(cost.first <= actual_cost && actual_cost <= cost.second) {
675 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
677 int actual_cost = args.u.jamming_cost(args.context().get_disp_context().map().get_terrain(args.loc));
678 for(
auto cost : ranges) {
679 if(cost.first <= actual_cost && actual_cost <= cost.second) {
692 return lk->run_filter(lua_function.c_str(), args.u);
732 if (
const game_data * gd = args.context().get_game_data()) {
735 for (
const config& c : gd->get_variable_access_read(find_in).as_array())
737 if(c[
"id"] == args.u.id()) {
752 if (!literal[
"x"].
blank() || !literal[
"y"].blank()) {
753 children_.emplace_back(
new unit_filter_xy(literal[
"x"], literal[
"y"]));
759 cond_children_.emplace_back(std::piecewise_construct_t(), std::tuple(*cond), std::tuple(child.second));
761 else if (child.first ==
"filter_wml") {
763 config fwml = c.get_parsed_config();
767 config::all_children_itors ci = fwml.all_children_range();
768 if (fwml.all_children_count() == 1 && fwml.attribute_count() == 1 && ci.front().key ==
"variables") {
769 return args.u.variables().matches(ci.front().cfg);
773 return ucfg.matches(fwml);
777 else if (child.first ==
"filter_vision") {
779 std::set<int> viewers;
780 side_filter ssf(c, args.fc);
781 std::vector<int> sides = ssf.get_teams();
782 viewers.insert(sides.begin(), sides.end());
784 for (const int viewer : viewers) {
785 bool fogged = args.context().get_disp_context().get_team(viewer).fogged(args.loc);
787 bool hiding = args.context().get_disp_context().get_team(viewer).is_enemy(args.u.side()) && args.u.invisible(args.loc);
788 bool unit_hidden = fogged || hiding;
789 if (c[
"visible"].to_bool(true) != unit_hidden) {
796 else if (child.first ==
"filter_adjacent") {
797 children_.emplace_back(
new unit_filter_adjacent(child.second));
799 else if (child.first ==
"filter_location") {
801 return terrain_filter(c, args.fc, args.use_flat_tod).match(args.loc);
804 else if (child.first ==
"filter_side") {
806 return side_filter(c, args.fc).match(args.u.side());
809 else if (child.first ==
"has_attack") {
811 for(const attack_type& a : args.u.attacks()) {
812 if(a.matches_filter(c.get_parsed_config())) {
820 std::stringstream errmsg;
821 errmsg <<
"encountered a child [" << child.first <<
"] of a standard unit filter, it is being ignored";
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 "".
static display * get_singleton()
Returns the display object if a display object exists.
const_all_children_itors all_children_range() const
In-order iteration over all children.
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
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.
virtual const display_context & get_disp_context() const =0
const filter_context * fc_
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
The unit cannot be healed.
This class represents a single unit of a specific type.
int main(int, char **argv)
Variant for storing WML attributes.
void create_child(const vconfig &c, F func)
bool operator()(const unit &u, const map_location &loc) const
const unit_map & get_units() const
unit_type_data unit_types
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp >> &ranges)
bool matches(const unit &u, const map_location &loc) const
Determine if *this matches filter at a specified location.
bool filter_impl(const unit_filter_args &u) const
const filter_context & context() const
static std::vector< DIRECTION > parse_directions(const std::string &str)
Parse_directions takes a comma-separated list, and filters out any invalid directions.
Definitions for the interface to Wesnoth Markup Language (WML).
virtual const gamemap & map() const =0
A single unit type that the player may recruit.
utils::variant< upkeep_full, upkeep_loyal, int > upkeep_t
std::shared_ptr< const unit > unit_const_ptr
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_
filter_context * filter_con
bool blank() const
Tests for an attribute that was never set.
std::vector< std::pair< conditional_type::type, unit_filter_compound > > cond_children_
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
static const std::vector< DIRECTION > & default_dirs()
Default list of directions.
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 filter_context * fc
Encapsulates the map of the game.
unit_iterator find(std::size_t id)
unit_const_ptr first_match_on_map() const
std::vector< std::shared_ptr< unit_filter_base > > children_
Visitor helper class to fetch the appropriate upkeep value.
static constexpr std::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
static map_location::DIRECTION s
bool on_board(const map_location &loc) const
Tell if a location is on the map.
DIRECTION
Valid directions which can be moved in our hexagonal world.
bool to_bool(bool def=false) const
bool matches_range(const std::string &xloc, const std::string &yloc) const
void create_attribute(const config::attribute_value c, C conv, F func)
std::vector< const unit * > all_matches_on_map(const map_location *loc=nullptr, const unit *other_unit=nullptr) const
std::vector< std::string > split(const config_attribute_value &val)
const map_location & get_location() const
The current map location this unit is at.
A variable-expanding proxy for the config class.
const config & get_config() const
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.
int side() const
The side this unit belongs to.
Visitor helper class to parse the upkeep value from a config.
bool as_bool() const
Returns a boolean state of the variant value.
A config object defines a single node in a WML file, with access to child nodes.
virtual bool matches(const unit_filter_args &u) const override
bool has_variation(const std::string &variation_id) const
static lg::log_domain log_wml("wml")
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
std::string str(const std::string &fallback="") const
boost::iterator_range< all_children_iterator > all_ordered() const
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.