move filter_abilitie/specials code in abilities.cpp

The code was moved to abilities.cpp so that it can be called from the units or attack_type functions, the attack_type function state necessary for the tags [filter_special_active] and [remove_specials] which I plan to implement when the code for filter_ability] is validated in its final form.
This commit is contained in:
newfrenchy83 2024-03-13 14:04:57 +01:00 committed by Pentarctagon
parent 788cedc99a
commit 24859f861a
3 changed files with 151 additions and 130 deletions

View file

@ -35,6 +35,7 @@
#include "units/abilities.hpp"
#include "units/filter.hpp"
#include "units/map.hpp"
#include "utils/config_filters.hpp"
#include "filter_context.hpp"
#include "formula/callable_objects.hpp"
#include "formula/formula.hpp"
@ -1524,9 +1525,7 @@ bool attack_type::overwrite_special_checking(unit_ability_list& overwriters, con
if(overwrite_specials){
auto overwrite_filter = (*overwrite_specials).optional_child("experimental_filter_specials");
if(overwrite_filter && is_overwritable && one_side_overwritable){
if(self_){
special_matches = (*self_).ability_matches_filter(cfg, tag_name, *overwrite_filter);
}
special_matches = special_matches_filter(cfg, tag_name, *overwrite_filter);
}
}
@ -1743,6 +1742,146 @@ bool attack_type::has_special_or_ability(const std::string& special, bool specia
}
//end of emulate weapon special functions.
namespace
{
bool matches_ability_filter(const config & cfg, const std::string& tag_name, const config & filter)
{
using namespace utils::config_filters;
if(!filter["affect_adjacent"].empty()){
bool adjacent = cfg.has_child("affect_adjacent");
if(filter["affect_adjacent"].to_bool() != adjacent){
return false;
}
}
if(!bool_matches_if_present(filter, cfg, "affect_self", true))
return false;
if(!bool_or_empty(filter, cfg, "affect_allies"))
return false;
if(!bool_matches_if_present(filter, cfg, "affect_enemies", false))
return false;
if(!bool_matches_if_present(filter, cfg, "cumulative", false))
return false;
const std::vector<std::string> filter_type = utils::split(filter["tag_name"]);
if ( !filter_type.empty() && std::find(filter_type.begin(), filter_type.end(), tag_name) == filter_type.end() )
return false;
if(!string_matches_if_present(filter, cfg, "id", ""))
return false;
if(tag_name == "resistance"){
if(!set_includes_if_present(filter, cfg, "apply_to")){
return false;
}
} else {
if(!string_matches_if_present(filter, cfg, "apply_to", "self")){
return false;
}
}
if(!string_matches_if_present(filter, cfg, "overwrite_specials", "none"))
return false;
if(!string_matches_if_present(filter, cfg, "active_on", "both"))
return false;
//for damage only
if(!string_matches_if_present(filter, cfg, "replacement_type", ""))
return false;
if(!string_matches_if_present(filter, cfg, "alternative_type", ""))
return false;
//for plague only
if(!string_matches_if_present(filter, cfg, "type", ""))
return false;
if(!filter["value"].empty()){
if(tag_name == "drains"){
if(!int_matches_if_present(filter, cfg, "value", 50)){
return false;
}
} else if(tag_name == "berserk"){
if(!int_matches_if_present(filter, cfg, "value", 1)){
return false;
}
} else if(tag_name == "heal_on_hit" || tag_name == "heals" || tag_name == "regenerate" || tag_name == "leadership"){
if(!int_matches_if_present(filter, cfg, "value" , 0)){
return false;
}
} else {
if(!int_matches_if_present(filter, cfg, "value")){
return false;
}
}
}
if(!int_matches_if_present_or_negative(filter, cfg, "add", "sub"))
return false;
if(!int_matches_if_present_or_negative(filter, cfg, "sub", "add"))
return false;
if(!double_matches_if_present(filter, cfg, "multiply"))
return false;
if(!double_matches_if_present(filter, cfg, "divide"))
return false;
//the wml_filter is used in cases where the attribute we are looking for is not
//previously listed or to check the contents of the sub_tags ([filter_adjacent],[filter_self],[filter_opponent] etc.
//If the checked set does not exactly match the content of the capability, the function returns a false response.
auto fwml = filter.optional_child("filter_wml");
if (fwml){
if(!cfg.matches(*fwml)){
return false;
}
}
// Passed all tests.
return true;
}
static bool common_matches_filter(const config & cfg, const std::string& tag_name, const config & filter)
{
// Handle the basic filter.
bool matches = matches_ability_filter(cfg, tag_name, filter);
// Handle [and], [or], and [not] with in-order precedence
for (const config::any_child condition : filter.all_children_range() )
{
// Handle [and]
if ( condition.key == "and" )
matches = matches && common_matches_filter(cfg, tag_name, condition.cfg);
// Handle [or]
else if ( condition.key == "or" )
matches = matches || common_matches_filter(cfg, tag_name, condition.cfg);
// Handle [not]
else if ( condition.key == "not" )
matches = matches && !common_matches_filter(cfg, tag_name, condition.cfg);
}
return matches;
}
}
bool unit::ability_matches_filter(const config & cfg, const std::string& tag_name, const config & filter) const
{
return common_matches_filter(cfg, tag_name, filter);
}
bool attack_type::special_matches_filter(const config & cfg, const std::string& tag_name, const config & filter) const
{
return common_matches_filter(cfg, tag_name, filter);
}
bool attack_type::special_active(const config& special, AFFECTS whom, const std::string& tag_name,
const std::string& filter_self) const
{

View file

@ -155,6 +155,15 @@ private:
// Configured as a bit field, in case that is useful.
enum AFFECTS { AFFECT_SELF=1, AFFECT_OTHER=2, AFFECT_EITHER=3 };
/**
* Filter a list of abilities or weapon specials
* @param cfg config of ability checked
* @param tag_name le type of ability who is checked
* @param filter config contain list of attribute who are researched in cfg
*
* @return true if all attribute with ability checked
*/
bool special_matches_filter(const config & cfg, const std::string& tag_name, const config & filter) const;
/**
* Filter a list of abilities or weapon specials, removing any entries that don't own
* the overwrite_specials attributes.

View file

@ -1442,133 +1442,6 @@ void unit::remove_ability_by_id(const std::string& ability)
}
}
static bool matches_ability_filter(const config & cfg, const std::string& tag_name, const config & filter)
{
using namespace utils::config_filters;
if(!filter["affect_adjacent"].empty()){
bool adjacent = cfg.has_child("affect_adjacent");
if(filter["affect_adjacent"].to_bool() != adjacent){
return false;
}
}
if(!bool_matches_if_present(filter, cfg, "affect_self", true))
return false;
if(!bool_or_empty(filter, cfg, "affect_allies"))
return false;
if(!bool_matches_if_present(filter, cfg, "affect_enemies", false))
return false;
if(!bool_matches_if_present(filter, cfg, "cumulative", false))
return false;
const std::vector<std::string> filter_type = utils::split(filter["tag_name"]);
if ( !filter_type.empty() && std::find(filter_type.begin(), filter_type.end(), tag_name) == filter_type.end() )
return false;
if(!string_matches_if_present(filter, cfg, "id", ""))
return false;
if(tag_name == "resistance"){
if(!set_includes_if_present(filter, cfg, "apply_to")){
return false;
}
} else {
if(!string_matches_if_present(filter, cfg, "apply_to", "self")){
return false;
}
}
if(!string_matches_if_present(filter, cfg, "overwrite_specials", "none"))
return false;
if(!string_matches_if_present(filter, cfg, "active_on", "both"))
return false;
//for damage only
if(!string_matches_if_present(filter, cfg, "replacement_type", ""))
return false;
if(!string_matches_if_present(filter, cfg, "alternative_type", ""))
return false;
//for plague only
if(!string_matches_if_present(filter, cfg, "type", ""))
return false;
if(!filter["value"].empty()){
if(tag_name == "drains"){
if(!int_matches_if_present(filter, cfg, "value", 50)){
return false;
}
} else if(tag_name == "berserk"){
if(!int_matches_if_present(filter, cfg, "value", 1)){
return false;
}
} else if(tag_name == "heal_on_hit" || tag_name == "heals" || tag_name == "regenerate" || tag_name == "leadership"){
if(!int_matches_if_present(filter, cfg, "value" , 0)){
return false;
}
} else {
if(!int_matches_if_present(filter, cfg, "value")){
return false;
}
}
}
if(!int_matches_if_present_or_negative(filter, cfg, "add", "sub"))
return false;
if(!int_matches_if_present_or_negative(filter, cfg, "sub", "add"))
return false;
if(!double_matches_if_present(filter, cfg, "multiply"))
return false;
if(!double_matches_if_present(filter, cfg, "divide"))
return false;
//the wml_filter is used in cases where the attribute we are looking for is not
//previously listed or to check the contents of the sub_tags ([filter_adjacent],[filter_self],[filter_opponent] etc.
//If the checked set does not exactly match the content of the capability, the function returns a false response.
auto fwml = filter.optional_child("filter_wml");
if (fwml){
if(!cfg.matches(*fwml)){
return false;
}
}
// Passed all tests.
return true;
}
bool unit::ability_matches_filter(const config & cfg, const std::string& tag_name, const config & filter) const
{
// Handle the basic filter.
bool matches = matches_ability_filter(cfg, tag_name, filter);
// Handle [and], [or], and [not] with in-order precedence
for (const config::any_child condition : filter.all_children_range() )
{
// Handle [and]
if ( condition.key == "and" )
matches = matches && ability_matches_filter(cfg, tag_name, condition.cfg);
// Handle [or]
else if ( condition.key == "or" )
matches = matches || ability_matches_filter(cfg, tag_name, condition.cfg);
// Handle [not]
else if ( condition.key == "not" )
matches = matches && !ability_matches_filter(cfg, tag_name, condition.cfg);
}
return matches;
}
void unit::remove_ability_by_attribute(const config& filter)
{
set_attr_changed(UA_ABILITIES);