Enable filtering by upkeep in SUF

Supports both numeric values and the special values loyal, free, full.

Closes #3333
This commit is contained in:
Celtic Minstrel 2019-11-09 19:49:31 -05:00
parent 61963d71c9
commit f82fdb224e
3 changed files with 54 additions and 10 deletions

View file

@ -433,6 +433,21 @@ void unit_filter_compound::fill(vconfig cfg)
return gender == args.u.gender();
}
);
create_attribute(literal["upkeep"],
[](const config::attribute_value& c) -> unit::upkeep_t
{
try {
return c.apply_visitor(unit::upkeep_parser_visitor());
} catch(std::invalid_argument&) {
return unit::upkeep_full();
}
},
[](unit::upkeep_t upkeep, const unit_filter_args& args)
{
return args.u.upkeep() == boost::apply_visitor(unit::upkeep_value_visitor(args.u), upkeep);
}
);
create_attribute(literal["side"],
[](const config::attribute_value& c)

View file

@ -2635,16 +2635,10 @@ void unit::parse_upkeep(const config::attribute_value& upkeep)
return;
}
// TODO: create abetter way to check whether it is actually an int.
int upkeep_int = upkeep.to_int(-99);
if(upkeep_int != -99) {
upkeep_ = upkeep_int;
} else if(upkeep == upkeep_loyal::type() || upkeep == "free") {
upkeep_ = upkeep_loyal();
} else if(upkeep == upkeep_full::type()) {
upkeep_ = upkeep_full();
} else {
WRN_UT << "Found invalid upkeep=\"" << upkeep << "\" in a unit" << std::endl;
try {
upkeep_ = upkeep.apply_visitor(upkeep_parser_visitor());
} catch(std::invalid_argument& e) {
WRN_UT << "Found invalid upkeep=\"" << e.what() << "\" in a unit" << std::endl;
upkeep_ = upkeep_full();
}
}

View file

@ -1132,6 +1132,41 @@ public:
};
using upkeep_t = boost::variant<upkeep_full, upkeep_loyal, int>;
/** Visitor helper class to parse the upkeep value from a config. */
class upkeep_parser_visitor : public boost::static_visitor<upkeep_t>
{
public:
template<typename N>
std::enable_if_t<std::is_arithmetic<N>::value, upkeep_t>
operator()(N n) const
{
if(n == 0) return upkeep_loyal();
if(n < 0) throw std::invalid_argument(std::to_string(n));
return n;
}
template<typename B>
std::enable_if_t<std::is_convertible<B, bool>::value && !std::is_arithmetic<B>::value, upkeep_t>
operator()(B b) const
{
throw std::invalid_argument(b.str());
}
upkeep_t operator()(boost::blank) const
{
return upkeep_full();
}
upkeep_t operator()(const std::string& s) const
{
if(s == "loyal" || s == "free")
return upkeep_loyal();
if(s == "full")
return upkeep_full();
throw std::invalid_argument(s);
}
};
/**
* Gets the raw variant controlling the upkeep value.