33 #include "formula/callable_objects.hpp"
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)
46 #define ERR_WML LOG_STREAM(err, log_wml)
53 , use_flat_tod_(false)
69 std::vector<const unit *> ret;
74 if(max_matches == 0) {
87 if (
matches(*u, u->get_location())) {
88 return u.get_shared_ptr();
98 unit_filter_xy(
const std::string& x,
const std::string& y) : x_(x), y_(y) {}
105 if(x.empty() && y.empty()) {
108 else if(x ==
"recall" && y ==
"recall") {
116 const std::string x_;
117 const std::string y_;
122 unit_filter_adjacent(
const vconfig& cfg)
135 std::vector<map_location::direction> dirs;
136 if (i_adjacent.
empty()) {
143 if (unit_itor == units.
end() || !child_.matches(
unit_filter_args{*unit_itor, unit_itor->get_location(), &args.u, args.fc, args.use_flat_tod} )) {
146 auto is_enemy = cfg_[
"is_enemy"];
166 unit_filter_child_literal(
const vconfig& v,
const F&
f) : v_(v) , f_(
f) {}
175 template<
typename T,
typename F>
178 unit_filter_attribute_parsed(T&& v, F&&
f) : v_(std::move(v)), f_(std::move(
f)) {}
187 template<
typename C,
typename F>
190 unit_filter_attribute_literal(std::string&& v, C&&
c, F&&
f) : v_(std::move(v)), c_(std::move(
c)), f_(std::move(
f)) {}
195 return f_(c_(v), args);
202 class contains_dollar_visitor
203 #ifdef USING_BOOST_VARIANT
204 :
public boost::static_visitor<bool>
208 contains_dollar_visitor() {}
212 bool operator()(
const T&)
const {
return false; }
214 bool operator()(
const t_string&)
const {
return true; }
216 bool operator()(
const std::string&
s)
const
218 return s.find(
'$') != std::string::npos;
225 unit_filter_compound::unit_filter_compound(
const vconfig& cfg)
253 case conditional_type::type::filter_and:
254 res = res &&
filter.second.matches(args);
256 case conditional_type::type::filter_or:
257 res = res ||
filter.second.matches(args);
259 case conditional_type::type::filter_not:
260 res = res && !
filter.second.matches(args);
270 if (!
filter->matches(args)) {
280 children_.emplace_back(
new unit_filter_child_literal<F>(
c, func));
283 template<
typename C,
typename F>
289 children_.emplace_back(
new unit_filter_attribute_literal<C, F>(std::move(v.
str()), std::move(conv), std::move(func)));
292 children_.emplace_back(
new unit_filter_attribute_parsed<decltype(conv(v)), F>(std::move(conv(v)), std::move(func)));
300 std::string tag_name;
304 void get_ability_children_id(std::vector<ability_match>& id_result,
305 const config& parent,
const std::string&
id) {
308 if(cfg[
"id"] ==
id) {
309 ability_match special = { key, &cfg };
310 id_result.push_back(special);
321 if(literal.
empty()) {
return; }
332 return std::find(id_list.begin(), id_list.end(), args.
u.
id()) != id_list.end();
348 std::set<std::string> types_expanded;
349 for(
const std::string&
type : types) {
350 if(types_expanded.count(
type)) {
354 const auto& tree = ut->advancement_tree();
355 types_expanded.insert(tree.begin(), tree.end());
356 types_expanded.insert(
type);
359 return types_expanded.find(args.
u.
type_id()) != types_expanded.end();
379 for(
const std::string& variation_id : types) {
380 if (
type->has_variation(variation_id)) {
392 for(
const std::string& ability_id : abilities) {
405 for(
const std::string& ability : abilities) {
419 for(
const std::string& ability : abilities) {
420 std::vector<ability_match> ability_id_matches_self;
421 get_ability_children_id(ability_id_matches_self, args.
u.
abilities(), ability);
422 for(
const ability_match& entry : ability_id_matches_self) {
437 utils::optional<int> dir;
439 for(std::size_t j = 0; j < adjacent.size(); ++j) {
440 bool adj_or_dist = distance != 1 ?
distance_between(adjacent[j], args.
loc) == (distance - 1) : adjacent[j] == args.
loc;
446 std::vector<ability_match> ability_id_matches_adj;
447 get_ability_children_id(ability_id_matches_adj,
unit.
abilities(), ability);
448 for(
const ability_match& entry : ability_id_matches_adj) {
463 for(
const std::string& ability : abilities) {
476 std::sort(res.begin(), res.end());
480 [](
const std::vector<std::string>& check_traits,
const unit_filter_args& args)
484 std::vector<std::string> isect;
485 std::sort(have_traits.begin(), have_traits.end());
486 std::set_intersection(check_traits.begin(), check_traits.end(), have_traits.begin(), have_traits.end(), std::back_inserter(isect));
487 return !isect.empty();
495 return std::find(races.begin(), races.end(), args.
u.
race()->
id()) != races.end();
503 return gender == args.
u.
gender();
512 }
catch(std::invalid_argument&) {
525 std::vector<int> res;
528 res.push_back(std::stoi(s));
529 }
catch(std::invalid_argument&) {
530 WRN_CF <<
"ignored invalid side='" << s <<
"' in filter";
537 return std::find(sides.begin(), sides.end(), args.
u.
side()) != sides.end();
541 create_attribute(literal[
"status"],
545 for(
const std::string& status : statuses) {
554 create_attribute(literal[
"has_weapon"],
560 if(a.id() == weapon) {
568 create_attribute(literal[
"role"],
576 create_attribute(literal[
"alignment"],
584 create_attribute(literal[
"ai_special"],
592 create_attribute(literal[
"usage"],
596 for(
const std::string& usage : usages) {
597 if(args.
u.
usage() == usage) {
605 create_attribute(literal[
"canrecruit"],
613 create_attribute(literal[
"recall_cost"],
615 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
621 create_attribute(literal[
"level"],
623 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
629 create_attribute(literal[
"defense"],
631 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
634 return in_ranges(actual_defense, ranges);
638 create_attribute(literal[
"movement_cost"],
640 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
647 create_attribute(literal[
"vision_cost"],
649 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
656 create_attribute(literal[
"jamming_cost"],
658 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
665 create_attribute(literal[
"lua_function"],
676 create_attribute(literal[
"formula"],
682 lg::log_to_chat() <<
"Formula error while evaluating formula in unit filter: " <<
e.type <<
" at "
683 <<
e.filename <<
':' <<
e.line <<
")\n";
684 ERR_WML <<
"Formula error while evaluating formula in unit filter: " <<
e.type <<
" at "
685 <<
e.filename <<
':' <<
e.line <<
")";
695 auto secondary = std::make_shared<wfl::unit_callable>(*args.
u2);
704 lg::log_to_chat() <<
"Formula error in unit filter: " <<
e.type <<
" at " <<
e.filename <<
':' <<
e.line <<
")\n";
705 ERR_WML <<
"Formula error in unit filter: " <<
e.type <<
" at " <<
e.filename <<
':' <<
e.line <<
")";
712 create_attribute(literal[
"find_in"],
720 for (
const config&
c : gd->get_variable_access_read(find_in).as_array())
722 if(
c[
"id"] == args.
u.
id()) {
737 if (!literal[
"x"].
blank() || !literal[
"y"].blank()) {
738 children_.emplace_back(
new unit_filter_xy(literal[
"x"], literal[
"y"]));
741 for(
auto child : cfg.all_ordered()) {
744 cond_children_.emplace_back(std::piecewise_construct_t(), std::tuple(*cond), std::tuple(child.second));
746 else if (child.first ==
"filter_wml") {
748 config fwml = c.get_parsed_config();
752 config::all_children_itors ci = fwml.all_children_range();
753 if (fwml.all_children_count() == 1 && fwml.attribute_count() == 1 && ci.front().key ==
"variables") {
754 return args.u.variables().matches(ci.front().cfg);
758 return ucfg.matches(fwml);
762 else if (child.first ==
"filter_vision") {
764 std::set<int> viewers;
765 side_filter ssf(c, args.fc);
766 std::vector<int> sides = ssf.get_teams();
767 viewers.insert(sides.begin(), sides.end());
769 for (const int viewer : viewers) {
770 bool fogged = args.context().get_disp_context().get_team(viewer).fogged(args.loc);
772 bool hiding = args.context().get_disp_context().get_team(viewer).is_enemy(args.u.side()) && args.u.invisible(args.loc);
773 bool unit_hidden = fogged || hiding;
774 if (c[
"visible"].to_bool(true) != unit_hidden) {
781 else if (child.first ==
"filter_adjacent") {
782 children_.emplace_back(
new unit_filter_adjacent(child.second));
784 else if (child.first ==
"filter_location") {
786 return terrain_filter(c, args.fc, args.use_flat_tod).match(args.loc);
789 else if (child.first ==
"filter_side") {
791 return side_filter(c, args.fc).match(args.u.side());
794 else if ((child.first ==
"filter_ability") || (child.first ==
"experimental_filter_ability")) {
795 if(child.first ==
"experimental_filter_ability"){
799 if(!(c.get_parsed_config())[
"active"].to_bool()){
800 for(const auto [key, cfg] : args.u.abilities().all_children_view()) {
801 if(args.u.ability_matches_filter(cfg, key, c.get_parsed_config())) {
806 const unit_map& units = args.context().get_disp_context().units();
807 for(const auto [key, cfg] : args.u.abilities().all_children_view()) {
808 if(args.u.ability_matches_filter(cfg, key, c.get_parsed_config())) {
809 if (args.u.get_self_ability_bool(cfg, key, args.loc)) {
815 if(
c.get_parsed_config()[
"affect_adjacent"].to_bool(
true)) {
816 for(const unit& unit : units) {
817 if(!unit.has_ability_distant() || unit.incapacitated() || &unit == args.u.shared_from_this().get()) {
820 const map_location& from_loc = unit.get_location();
821 std::size_t distance = distance_between(from_loc, args.loc);
822 if(distance > *unit.has_ability_distant()) {
825 utils::optional<int> dir;
826 const auto adjacent = get_adjacent_tiles(from_loc);
827 for(std::size_t j = 0; j < adjacent.size(); ++j) {
828 bool adj_or_dist = distance != 1 ? distance_between(adjacent[j], args.loc) == (distance - 1) : adjacent[j] == args.loc;
834 for(const auto [key, cfg] : unit.abilities().all_children_view()) {
835 if(args.u.get_adj_ability_bool(cfg, key, distance, *dir, args.loc, unit, from_loc)) {
845 else if (child.first ==
"has_attack") {
847 for(const attack_type& a : args.u.attacks()) {
848 if(a.matches_filter(c.get_parsed_config())) {
856 std::stringstream errmsg;
857 errmsg <<
"encountered a child [" << child.first <<
"] of a standard unit filter, it is being ignored";
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.
auto all_children_view() const
In-order iteration over all children.
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.
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.
unit_iterator find(std::size_t id)
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.
const config & get_config() const
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.
bool get_adj_ability_bool(const config &cfg, const std::string &ability, std::size_t dist, int dir, const map_location &loc, const unit &from, const map_location &from_loc) const
Checks whether this unit is affected by a given ability, and that that ability is active.
bool has_ability_type(const std::string &ability) const
Check if the unit has an ability of a specific type.
unit_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 get_self_ability_bool(const config &cfg, const std::string &ability, const map_location &loc) const
Checks whether this unit currently possesses a given ability, and that that ability is active.
bool has_ability_by_id(const std::string &ability) const
Check if the unit has an ability of a specific ID.
const config & abilities() const
unit_alignments::type alignment() const
The alignment of this unit.
bool incapacitated() const
Check if the unit has been petrified.
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.
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.
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
attack_itors attacks()
Gets an iterator over this unit's attacks.
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::optional< std::size_t > has_ability_distant() const
Gets if this unit own ability with [affect_adjacent] subtags.
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.
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
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.
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::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...
std::vector< std::string > split(const config_attribute_value &val)
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
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.
static std::vector< direction > all_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")