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()) {
144 if (unit_itor == units.
end() || !child_.matches(
unit_filter_args{*unit_itor, unit_itor->get_location(), &args.u, args.fc, args.use_flat_tod} )) {
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; }
215 bool operator()(
const t_string&)
const {
return true; }
217 bool operator()(
const std::string&
s)
const
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) {
381 if (
type->has_variation(variation_id)) {
393 for(
const std::string& ability_id : abilities) {
406 for(
const std::string& ability : abilities) {
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) {
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) {
455 for(
const std::string& ability : abilities) {
468 std::sort(res.begin(), res.end());
472 [](
const std::vector<std::string>& check_traits,
const unit_filter_args& args)
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();
533 create_attribute(literal[
"status"],
537 for(
const std::string& status : statuses) {
546 create_attribute(literal[
"has_weapon"],
552 if(
a.id() == weapon) {
560 create_attribute(literal[
"role"],
568 create_attribute(literal[
"alignment"],
576 create_attribute(literal[
"ai_special"],
584 create_attribute(literal[
"usage"],
588 for(
const std::string& usage : usages) {
589 if(args.
u.
usage() == usage) {
597 create_attribute(literal[
"canrecruit"],
605 create_attribute(literal[
"recall_cost"],
607 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
609 for(
auto cost : ranges) {
618 create_attribute(literal[
"level"],
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) {
631 create_attribute(literal[
"defense"],
633 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
636 for(
auto def : ranges) {
637 if(def.first <= actual_defense && actual_defense <= def.second) {
645 create_attribute(literal[
"movement_cost"],
647 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
650 for(
auto cost : ranges) {
651 if(cost.first <= actual_cost && actual_cost <= cost.second) {
659 create_attribute(literal[
"vision_cost"],
661 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
664 for(
auto cost : ranges) {
665 if(cost.first <= actual_cost && actual_cost <= cost.second) {
673 create_attribute(literal[
"jamming_cost"],
675 [](
const std::vector<std::pair<int,int>>& ranges,
const unit_filter_args& args)
678 for(
auto cost : ranges) {
679 if(cost.first <= actual_cost && actual_cost <= cost.second) {
687 create_attribute(literal[
"lua_function"],
698 create_attribute(literal[
"formula"],
710 auto secondary = std::make_shared<wfl::unit_callable>(*args.
u2);
719 lg::log_to_chat() <<
"Formula error in unit filter: " <<
e.type <<
" at " <<
e.filename <<
':' <<
e.line <<
")\n";
720 ERR_WML <<
"Formula error in unit filter: " <<
e.type <<
" at " <<
e.filename <<
':' <<
e.line <<
")";
727 create_attribute(literal[
"find_in"],
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"]));
756 for(
auto child : cfg.all_ordered()) {
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 ==
"filter_ability") {
811 for(const config::any_child ab : args.u.abilities().all_children_range()) {
812 if(args.u.ability_matches_filter(ab.cfg, ab.key, c.get_parsed_config())) {
819 else if (child.first ==
"filter_ability_active") {
821 if(!display::get_singleton()){
826 if(args.u.ability_matches_filter(ab.cfg, ab.key, c.get_parsed_config())) {
827 if (args.u.get_self_ability_bool(ab.cfg, ab.key, args.loc)) {
834 for(
unsigned i = 0;
i < adjacent.size(); ++
i) {
836 if (it == units.
end() || it->incapacitated())
838 if (&*it == (args.
u.shared_from_this()).get())
842 if(it->ability_matches_filter(ab.cfg, ab.key,
c.get_parsed_config())) {
852 else if (child.first ==
"has_attack") {
854 for(const attack_type& a : args.u.attacks()) {
855 if(a.matches_filter(c.get_parsed_config())) {
863 std::stringstream errmsg;
864 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.
const_all_children_itors all_children_range() 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
const unit_map & get_units() const
static display * get_singleton()
Returns the display object if a display object exists.
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.
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.
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_adj_ability_bool(const config &special, const std::string &tag_name, int dir, const map_location &loc, const unit &from) const
Checks whether this unit is affected by a given ability used like weapon.
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
bool get_self_ability_bool(const config &special, const std::string &tag_name, const map_location &loc) const
Checks whether this unit currently possesses a given ability used like weapon.
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.
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.
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has.
utils::variant< upkeep_full, upkeep_loyal, int > upkeep_t
void get_adjacent_tiles(const map_location &a, map_location *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::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)
std::shared_ptr< const unit > unit_const_ptr
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
int main(int, char **argv)
Encapsulates the map of the game.
static const std::vector< DIRECTION > & default_dirs()
Default list of directions.
DIRECTION
Valid directions which can be moved in our hexagonal world.
static std::vector< DIRECTION > parse_directions(const std::string &str)
Parse_directions takes a comma-separated list, and filters out any invalid directions.
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 std::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 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")