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_;
134 std::size_t radius = cfg_[
"radius"].to_int(1);
137 std::vector<map_location::direction> dirs;
138 for(
const unit& u : units) {
141 if(u.underlying_id() == args.
u.
underlying_id() || distance > radius || !child_.matches(
unit_filter_args{u, from_loc, &args.u, args.fc, args.use_flat_tod} )) {
145 for(
unsigned j = 0; j < adjacent.size(); ++j) {
146 bool adj_or_dist = distance != 1 ?
distance_between(adjacent[j], from_loc) == (distance - 1) : adjacent[j] == from_loc;
152 assert(dir >= 0 && dir <= 5);
154 if(!i_adjacent.
empty()) {
166 static std::vector<std::pair<int,int>>
default_counts = {{{1, std::numeric_limits<int>::max()}}};
179 unit_filter_child_literal(
const vconfig& v,
const F&
f) : v_(v) , f_(
f) {}
188 template<
typename T,
typename F>
191 unit_filter_attribute_parsed(T&& v, F&&
f) : v_(std::move(v)), f_(std::move(
f)) {}
200 template<
typename C,
typename F>
203 unit_filter_attribute_literal(std::string&& v, C&&
c, F&&
f) : v_(std::move(v)), c_(std::move(
c)), f_(std::move(
f)) {}
208 return f_(c_(v), args);
215 class contains_dollar_visitor
216 #ifdef USING_BOOST_VARIANT
217 :
public boost::static_visitor<bool>
221 contains_dollar_visitor() {}
225 bool operator()(
const T&)
const {
return false; }
227 bool operator()(
const t_string&)
const {
return true; }
229 bool operator()(
const std::string&
s)
const
231 return s.find(
'$') != std::string::npos;
238 unit_filter_compound::unit_filter_compound(
const vconfig&
cfg)
266 case conditional_type::type::filter_and:
267 res = res &&
filter.second.matches(args);
269 case conditional_type::type::filter_or:
270 res = res ||
filter.second.matches(args);
272 case conditional_type::type::filter_not:
273 res = res && !
filter.second.matches(args);
283 if (!
filter->matches(args)) {
293 children_.emplace_back(
new unit_filter_child_literal<F>(
c, func));
296 template<
typename C,
typename F>
302 children_.emplace_back(
new unit_filter_attribute_literal<C, F>(std::move(v.
str()), std::move(conv), std::move(func)));
305 children_.emplace_back(
new unit_filter_attribute_parsed<decltype(conv(v)), F>(std::move(conv(v)), std::move(func)));
311 const config& literal =
cfg.get_config();
314 if(literal.
empty()) {
return; }
341 std::set<std::string> types_expanded;
342 for(
const std::string&
type : types) {
343 if(types_expanded.count(
type)) {
347 const auto& tree = ut->advancement_tree();
348 types_expanded.insert(tree.begin(), tree.end());
349 types_expanded.insert(
type);
372 for(
const std::string& variation_id : types) {
373 if (
type->has_variation(variation_id)) {
385 for(
const std::string& ability_id : abilities) {
398 for(
const std::string& ability : abilities) {
419 for(
const std::string& ability : abilities) {
432 std::sort(res.begin(), res.end());
436 [](
const std::vector<std::string>& check_traits,
const unit_filter_args& args)
440 std::vector<std::string> isect;
441 std::sort(have_traits.begin(), have_traits.end());
442 std::set_intersection(check_traits.begin(), check_traits.end(), have_traits.begin(), have_traits.end(), std::back_inserter(isect));
443 return !isect.empty();
459 return gender == args.
u.
gender();
468 }
catch(std::invalid_argument&) {
481 std::vector<int> res;
484 res.push_back(std::stoi(s));
485 }
catch(std::invalid_argument&) {
486 WRN_CF <<
"ignored invalid side='" << s <<
"' in filter";
497 create_attribute(literal[
"status"],
501 for(
const std::string& status : statuses) {
510 create_attribute(literal[
"has_weapon"],
516 if(a.id() == weapon) {
524 create_attribute(literal[
"role"],
532 create_attribute(literal[
"alignment"],
540 create_attribute(literal[
"ai_special"],
548 create_attribute(literal[
"usage"],
552 for(
const std::string& usage : usages) {
553 if(args.
u.
usage() == usage) {
561 create_attribute(literal[
"canrecruit"],
569 create_attribute(literal[
"recall_cost"],
571 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
577 create_attribute(literal[
"level"],
579 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
585 create_attribute(literal[
"defense"],
587 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
590 return in_ranges(actual_defense, ranges);
594 create_attribute(literal[
"movement_cost"],
596 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
603 create_attribute(literal[
"vision_cost"],
605 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
612 create_attribute(literal[
"jamming_cost"],
614 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
621 create_attribute(literal[
"lua_function"],
632 create_attribute(literal[
"formula"],
638 lg::log_to_chat() <<
"Formula error while evaluating formula in unit filter: " <<
e.type <<
" at "
639 <<
e.filename <<
':' <<
e.line <<
")\n";
640 ERR_WML <<
"Formula error while evaluating formula in unit filter: " <<
e.type <<
" at "
641 <<
e.filename <<
':' <<
e.line <<
")";
651 auto secondary = std::make_shared<wfl::unit_callable>(*args.
u2);
660 lg::log_to_chat() <<
"Formula error in unit filter: " <<
e.type <<
" at " <<
e.filename <<
':' <<
e.line <<
")\n";
661 ERR_WML <<
"Formula error in unit filter: " <<
e.type <<
" at " <<
e.filename <<
':' <<
e.line <<
")";
668 create_attribute(literal[
"find_in"],
676 for (
const config&
c : gd->get_variable_access_read(
find_in).as_array())
678 if(
c[
"id"] == args.
u.
id()) {
693 if (!literal[
"x"].
blank() || !literal[
"y"].blank()) {
694 children_.emplace_back(
new unit_filter_xy(literal[
"x"], literal[
"y"]));
697 for(
auto child :
cfg.all_ordered()) {
700 cond_children_.emplace_back(std::piecewise_construct_t(), std::tuple(*cond), std::tuple(child.second));
702 else if (child.first ==
"filter_wml") {
704 config fwml = c.get_parsed_config();
708 config::all_children_itors ci = fwml.all_children_range();
709 if (fwml.all_children_count() == 1 && fwml.attribute_count() == 0 && ci.front().key ==
"variables") {
710 return args.u.variables().matches(ci.front().cfg);
714 return ucfg.matches(fwml);
718 else if (child.first ==
"filter_vision") {
720 std::set<int> viewers;
721 side_filter ssf(c, args.fc);
722 std::vector<int> sides = ssf.get_teams();
723 viewers.insert(sides.begin(), sides.end());
725 for (const int viewer : viewers) {
726 bool fogged = args.context().get_disp_context().get_team(viewer).fogged(args.loc);
728 bool hiding = args.context().get_disp_context().get_team(viewer).is_enemy(args.u.side()) && args.u.invisible(args.loc);
729 bool unit_hidden = fogged || hiding;
730 if (c[
"visible"].to_bool(true) != unit_hidden) {
737 else if (child.first ==
"filter_adjacent") {
738 children_.emplace_back(
new unit_filter_adjacent(child.second));
740 else if (child.first ==
"filter_location") {
742 return terrain_filter(c, args.fc, args.use_flat_tod).match(args.loc);
745 else if (child.first ==
"filter_side") {
747 return side_filter(c, args.fc).match(args.u.side());
750 else if ((child.first ==
"filter_ability") || (child.first ==
"experimental_filter_ability")) {
751 if(child.first ==
"experimental_filter_ability"){
755 if(!(c.get_parsed_config())[
"active"].to_bool()){
756 for(const ability_ptr& p_ab : args.u.abilities()) {
757 if(p_ab->matches_filter(c.get_parsed_config())) {
762 return specials_context_t::has_active_ability_matching_filter(args.u, args.loc, c.get_parsed_config());
767 else if (child.first ==
"has_attack") {
769 for(const attack_type& a : args.u.attacks()) {
770 if(a.matches_filter(c.get_parsed_config())) {
778 std::stringstream errmsg;
779 errmsg <<
"encountered a child [" << child.first <<
"] of a standard unit filter, it is being ignored";
static bool is_enemy(std::size_t side, std::size_t other_side)
Variant for storing WML attributes.
std::string str(const std::string &fallback="") const
auto apply_visitor(const V &visitor) const
Visitor support: Applies a visitor to the underlying variant.
bool blank() const
Tests for an attribute that was never set.
bool empty() const
Tests for an attribute that either was never set or was set to "".
A config object defines a single node in a WML file, with access to child nodes.
const team & get_team(int side) const
This getter takes a 1-based side number, not a 0-based team number.
virtual const gamemap & map() const =0
virtual const unit_map & units() const =0
virtual const display_context & get_disp_context() const =0
virtual game_lua_kernel * get_lua_kernel() const =0
virtual const game_data * get_game_data() const =0
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
static bool has_active_ability_id(const unit &un, map_location loc, const std::string &id)
bool is_enemy(int n) const
Visitor helper class to parse the upkeep value from a config.
Visitor helper class to fetch the appropriate upkeep value.
unit_filter(const vconfig &cfg)
const filter_context * fc_
bool matches(const unit &u, const map_location &loc) const
Determine if *this matches filter at a specified location.
std::vector< const unit * > all_matches_on_map(const map_location *loc=nullptr, const unit *other_unit=nullptr) const
unit_const_ptr first_match_on_map() const
unit_filter_impl::unit_filter_compound impl_
Container associating units to locations.
const std::string & id() 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.
A single unit type that the player may recruit.
const std::string & parent_id() const
The id of the original type from which this (variation) descended.
This class represents a single unit of a specific type.
A variable-expanding proxy for the config class.
bool as_bool() const
Returns a boolean state of the variant value.
Definitions for the interface to Wesnoth Markup Language (WML).
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Interfaces for manipulating version numbers of engine, add-ons, etc.
active_ability_list get_abilities(const std::string &tag_name, const map_location &loc) const
Gets the unit's active abilities of a particular type if it were on a specified location.
bool has_ability_type(const std::string &ability) const
Check if the unit has an ability of a specific type.
bool has_ability_by_id(const std::string &ability) const
Check if the unit has an ability of a specific ID.
unit_alignments::type alignment() const
The alignment of this unit.
int level() const
The current level of this unit.
std::string usage() const
Gets this unit's usage.
const std::string & get_role() const
Gets this unit's role.
int recall_cost() const
How much gold it costs to recall this unit, or -1 if the side's default recall cost is used.
const std::string & variation() const
The ID of the variation of this unit's type.
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
const std::string & type_id() const
The id of this unit's type.
const unit_race * race() const
Gets this unit's race.
const unit_type & type() const
This unit's type, accounting for gender and variation.
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
const std::string & id() const
Gets this unit's id.
int side() const
The side this unit belongs to.
std::size_t underlying_id() const
This unit's unique internal ID.
unit_race::GENDER gender() const
The gender of this unit.
const t_string & name() const
Gets this unit's translatable display name.
@ STATE_GUARDIAN
The unit cannot be healed.
attack_itors attacks()
Gets an iterator over this unit's attacks.
int defense_modifier(const t_translation::terrain_code &terrain, const map_location &loc) const
The unit's defense on a given terrain.
const map_location & get_location() const
The current map location this unit is at.
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit's movement cost on a particular terrain.
int vision_cost(const t_translation::terrain_code &terrain) const
Get the unit's vision cost on a particular terrain.
int jamming_cost(const t_translation::terrain_code &terrain) const
Get the unit's jamming cost on a particular terrain.
int upkeep() const
Gets the amount of gold this unit costs a side per turn.
utils::variant< upkeep_full, upkeep_loyal, int > upkeep_t
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has, including hidden traits.
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
void get_adjacent_tiles(const map_location &a, utils::span< map_location, 6 > res)
Function which, given a location, will place all adjacent locations in res.
Standard logging facilities (interface).
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp >> &ranges)
std::vector< std::pair< int, int > > default_counts
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
std::function< int(lua_State *)> lua_function
filter_context * filter_con
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with '$' in the string 'str' with the equivalent ...
std::set< std::string > split_set(std::string_view s, char sep, const int flags)
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
auto * find_if(Container &container, const Predicate &predicate)
Convenience wrapper for using find_if on a container without needing to comare to end()
std::vector< std::pair< int, int > > parse_ranges_unsigned(const std::string &str)
Handles a comma-separated list of inputs to parse_range, in a context that does not expect negative v...
auto find_in(Container &map, const Value &value) -> utils::optional_reference< typename Container::mapped_type >
std::vector< std::string > split(const config_attribute_value &val)
std::shared_ptr< const unit > unit_const_ptr
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
Encapsulates the map of the game.
static std::vector< direction > parse_directions(const std::string &str)
Parse_directions takes a comma-separated list, and filters out any invalid directions.
direction
Valid directions which can be moved in our hexagonal world.
bool matches_range(const std::string &xloc, const std::string &yloc) const
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
static constexpr utils::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
const filter_context & context() const
virtual bool matches(const unit_filter_args &) const =0
bool filter_impl(const unit_filter_args &u) const
void fill(const vconfig &cfg)
void create_child(const vconfig &c, F func)
void create_attribute(const config::attribute_value &c, C conv, F func)
std::vector< std::pair< conditional_type::type, unit_filter_compound > > cond_children_
virtual bool matches(const unit_filter_args &u) const override
std::vector< std::shared_ptr< unit_filter_base > > children_
static map_location::direction s
unit_type_data unit_types
static lg::log_domain log_wml("wml")
static lg::log_domain log_config("config")