diff --git a/src/reports.cpp b/src/reports.cpp index dc132a31848f..55dcb2744b05 100644 --- a/src/reports.cpp +++ b/src/reports.cpp @@ -802,6 +802,7 @@ static int attack_info(reports::context & rc, const attack_type &at, config &res add_text(res, flush(str), flush(tooltip)); } + at.set_specials_context_for_listing(); std::vector active; const std::vector > &specials = at.special_tooltips(&active); const size_t specials_size = specials.size(); diff --git a/src/unit_abilities.cpp b/src/unit_abilities.cpp index ece4ba461abc..a33a2f9aee5f 100644 --- a/src/unit_abilities.cpp +++ b/src/unit_abilities.cpp @@ -685,6 +685,7 @@ void attack_type::set_specials_context(const map_location& unit_loc, other_loc_ = other_loc; is_attacker_ = attacking; other_attack_ = other_attack; + is_for_listing_ = false; } /** @@ -699,6 +700,12 @@ void attack_type::set_specials_context(const map_location& loc, bool attacking) other_loc_ = map_location::null_location(); is_attacker_ = attacking; other_attack_ = NULL; + is_for_listing_ = false; +} + +void attack_type::set_specials_context_for_listing() const +{ + is_for_listing_ = true; } @@ -803,9 +810,10 @@ namespace { // Helpers for attack_type::special_active() const map_location & loc, const attack_type * weapon, const config & filter, + const bool for_listing, const std::string & child_tag) { - if (!loc.valid() || !u2.valid()) + if (for_listing && !loc.valid()) // The special's context was set to ignore this unit, so assume we pass. // (This is used by reports.cpp to show active specials when the // opponent is not known. From a player's perspective, the special @@ -817,10 +825,23 @@ namespace { // Helpers for attack_type::special_active() if ( !filter_child ) // The special does not filter on this unit, so we pass. return true; + + // If the primary unit doesn't exist, there's nothing to match + if (!un_it.valid()) { + return false; + } + + unit_filter ufilt(vconfig(filter_child), resources::filter_con); + + // If the other unit doesn't exist, try matching without it + if (!u2.valid()) { + return ufilt.matches(*un_it, loc); + } // Check for a unit match. - if ( !un_it.valid() || !unit_filter(vconfig(filter_child), resources::filter_con).matches(*un_it, loc, *u2)) + if (!ufilt.matches(*un_it, loc, *u2)) { return false; + } // Check for a weapon match. if ( const config & filter_weapon = filter_child.child("filter_weapon") ) { @@ -890,13 +911,13 @@ bool attack_type::special_active(const config& special, AFFECTS whom, const attack_type * def_weapon = is_attacker_ ? other_attack_ : this; // Filter the units involved. - if (!special_unit_matches(self, other, self_loc_, this, special, "filter_self")) + if (!special_unit_matches(self, other, self_loc_, this, special, is_for_listing_, "filter_self")) return false; - if (!special_unit_matches(other, self, other_loc_, other_attack_, special, "filter_opponent")) + if (!special_unit_matches(other, self, other_loc_, other_attack_, special, is_for_listing_, "filter_opponent")) return false; - if (!special_unit_matches(att, def, att_loc, att_weapon, special, "filter_attacker")) + if (!special_unit_matches(att, def, att_loc, att_weapon, special, is_for_listing_, "filter_attacker")) return false; - if (!special_unit_matches(def, att, def_loc, def_weapon, special, "filter_defender")) + if (!special_unit_matches(def, att, def_loc, def_weapon, special, is_for_listing_, "filter_defender")) return false; map_location adjacent[6]; @@ -907,13 +928,13 @@ bool attack_type::special_active(const config& special, AFFECTS whom, { size_t count = 0; std::vector dirs = map_location::parse_directions(i["adjacent"]); + unit_filter filter(vconfig(i), resources::filter_con); BOOST_FOREACH(const map_location::DIRECTION index, dirs) { if (index == map_location::NDIRECTIONS) continue; unit_map::const_iterator unit = units.find(adjacent[index]); - if ( unit == units.end() || - !unit_filter(vconfig(i), resources::filter_con).matches(*unit, adjacent[index], *self)) //TODO: Should this filter get precomputed? + if (unit == units.end() || !filter.matches(*unit, adjacent[index], *self)) return false; if (i.has_attribute("is_enemy")) { const display_context& dc = resources::filter_con->get_disp_context(); @@ -936,11 +957,11 @@ bool attack_type::special_active(const config& special, AFFECTS whom, { size_t count = 0; std::vector dirs = map_location::parse_directions(i["adjacent"]); + terrain_filter adj_filter(vconfig(i), resources::filter_con); BOOST_FOREACH(const map_location::DIRECTION index, dirs) { if (index == map_location::NDIRECTIONS) continue; - terrain_filter adj_filter(vconfig(i), resources::filter_con); if(!adj_filter.match(adjacent[index])) { return false; } diff --git a/src/unit_attack_type.hpp b/src/unit_attack_type.hpp index 2fe734bd61c2..15fa53b080a7 100644 --- a/src/unit_attack_type.hpp +++ b/src/unit_attack_type.hpp @@ -73,6 +73,7 @@ class attack_type void set_specials_context(const map_location& unit_loc, const map_location& other_loc, bool attacking, const attack_type *other_attack) const; void set_specials_context(const map_location& loc, bool attacking = true) const; + void set_specials_context_for_listing() const; /// Calculates the number of attacks this weapon has, considering specials. void modified_attacks(bool is_backstab, unsigned & min_attacks, @@ -105,6 +106,7 @@ class attack_type mutable map_location self_loc_, other_loc_; mutable bool is_attacker_; mutable const attack_type* other_attack_; + mutable bool is_for_listing_; t_string description_; std::string id_;