From b45a6fa04f46b1a41576c596c2e4bb2f8d3376cb Mon Sep 17 00:00:00 2001 From: "J. Tyne" Date: Sun, 23 Sep 2012 20:48:55 +0000 Subject: [PATCH] Push [and],[or],[not] tags from event weapon filters to all weapon filters. --- changelog | 2 ++ src/game_events.cpp | 29 +----------------------- src/unit_types.cpp | 55 +++++++++++++++++++++++++++++++++------------ 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/changelog b/changelog index b6944e42395..e306bf3f814 100644 --- a/changelog +++ b/changelog @@ -33,6 +33,8 @@ Version 1.11.0+svn: delayed shroud updates (which is still a major caveat). * Added [effect] apply_to=overlay * Added [terrain_type] max_light= and min_light=. + * Standardize weapon filters, supporting special=, [and], [or], and [not] + wherever weapons can be filtered. * Miscellaneous and bug fixes: * Fix invalid memory access crash resulting from deleting all saved games in the Load Game dialog diff --git a/src/game_events.cpp b/src/game_events.cpp index 703d84d72f8..4337829aa24 100644 --- a/src/game_events.cpp +++ b/src/game_events.cpp @@ -3365,34 +3365,7 @@ namespace game_events { return false; } const attack_type attack(cfg); - bool matches = attack.matches_filter(filter.get_parsed_config()); - - // Handle [and], [or], and [not] with in-order precedence - vconfig::all_children_iterator cond_i = filter.ordered_begin(); - vconfig::all_children_iterator cond_end = filter.ordered_end(); - while(cond_i != cond_end) - { - const std::string& cond_name = cond_i.get_key(); - const vconfig& cond_filter = cond_i.get_child(); - - // Handle [and] - if(cond_name == "and") - { - matches = matches && matches_special_filter(cfg, cond_filter); - } - // Handle [or] - else if(cond_name == "or") - { - matches = matches || matches_special_filter(cfg, cond_filter); - } - // Handle [not] - else if(cond_name == "not") - { - matches = matches && !matches_special_filter(cfg, cond_filter); - } - ++cond_i; - } - return matches; + return attack.matches_filter(filter.get_parsed_config()); } bool unit_matches_filter(const unit &u, const vconfig& filter) diff --git a/src/unit_types.cpp b/src/unit_types.cpp index 81f319644f8..3bdaeddd2bc 100644 --- a/src/unit_types.cpp +++ b/src/unit_types.cpp @@ -91,11 +91,10 @@ std::string attack_type::accuracy_parry_description() const } /** - * Returns whether or not *this matches the given @a filter. - * If @a ignore_special is set to true, then the special= attribute of the - * filter is ignored. + * Returns whether or not *this matches the given @a filter, ignoring the + * complexities introduced by [and], [or], and [not]. */ -bool attack_type::matches_filter(const config& filter) const +static bool matches_simple_filter(const attack_type & attack, const config & filter) { const std::vector& filter_range = utils::split(filter["range"]); const std::string& filter_damage = filter["damage"]; @@ -103,25 +102,53 @@ bool attack_type::matches_filter(const config& filter) const const std::vector filter_type = utils::split(filter["type"]); const std::string filter_special = filter["special"]; - if(filter_range.empty() == false && std::find(filter_range.begin(),filter_range.end(),range()) == filter_range.end()) - return false; - - if(filter_damage.empty() == false && !in_ranges(damage(), utils::parse_ranges(filter_damage))) { - return false; - } - - if(filter_name.empty() == false && std::find(filter_name.begin(),filter_name.end(),id()) == filter_name.end()) + if ( !filter_range.empty() && std::find(filter_range.begin(), filter_range.end(), attack.range()) == filter_range.end() ) return false; - if(filter_type.empty() == false && std::find(filter_type.begin(),filter_type.end(),type()) == filter_type.end()) + if ( !filter_damage.empty() && !in_ranges(attack.damage(), utils::parse_ranges(filter_damage)) ) return false; - if ( !filter_special.empty() && !get_special_bool(filter_special, true) ) + if ( !filter_name.empty() && std::find(filter_name.begin(), filter_name.end(), attack.id()) == filter_name.end() ) return false; + if ( !filter_type.empty() && std::find(filter_type.begin(), filter_type.end(), attack.type()) == filter_type.end() ) + return false; + + if ( !filter_special.empty() && !attack.get_special_bool(filter_special, true) ) + return false; + + // Passed all tests. return true; } +/** + * Returns whether or not *this matches the given @a filter. + */ +bool attack_type::matches_filter(const config& filter) const +{ + // Handle the basic filter. + bool matches = matches_simple_filter(*this, filter); + + // Handle [and], [or], and [not] with in-order precedence + BOOST_FOREACH( const config::any_child &condition, filter.all_children_range() ) + { + // Handle [and] + if ( condition.key == "and" ) + matches = matches && matches_filter(condition.cfg); + + // Handle [or] + else if ( condition.key == "or" ) + matches = matches || matches_filter(condition.cfg); + + // Handle [not] + else if ( condition.key == "not" ) + matches = matches && !matches_filter(condition.cfg); + } + + return matches; +} + + /** * Modifies *this using the specifications in @a cfg, but only if *this matches * @a cfg viewed as a filter.