diff --git a/src/actions/create.cpp b/src/actions/create.cpp index 530865bce6ef..6e8819c77b61 100644 --- a/src/actions/create.cpp +++ b/src/actions/create.cpp @@ -431,11 +431,8 @@ namespace { // Helpers for get_recalls() // Only units that match the leader's recall filter are valid. scoped_recall_unit this_unit("this_unit", save_id, leader_team.recall_list().find_index(recall_unit.id())); - const vconfig & rfilter = vconfig(leader->recall_filter()); - if ( unit_filter::matches_filter( rfilter, - recall_unit, - map_location::null_location(), - resources::filter_con) ) + const unit_filter ufilt(vconfig(leader->recall_filter()), resources::filter_con); + if ( ufilt(recall_unit, map_location::null_location()) ) { result.push_back(recall_unit_ptr); if ( already_added != NULL ) @@ -534,11 +531,8 @@ namespace { // Helpers for check_recall_location() scoped_recall_unit this_unit("this_unit", recall_team.save_id(), recall_team.recall_list().find_index(recall_unit.id())); - const vconfig & rfilter = vconfig(recaller.recall_filter()); - if ( !unit_filter::matches_filter(rfilter, - recall_unit, - map_location::null_location(), - resources::filter_con) ) + const unit_filter ufilt(vconfig(recaller.recall_filter()), resources::filter_con); + if ( !ufilt(recall_unit, map_location::null_location()) ) return RECRUIT_NO_ABLE_LEADER; // Make sure the unit is on a keep. diff --git a/src/ai/composite/goal.cpp b/src/ai/composite/goal.cpp index b8e39eeac279..d3f1399ba484 100644 --- a/src/ai/composite/goal.cpp +++ b/src/ai/composite/goal.cpp @@ -135,8 +135,9 @@ void target_unit_goal::add_targets(std::back_insert_iterator< std::vector< targe if (!criteria) return; //find the enemy leaders and explicit targets + const unit_filter ufilt(vconfig(criteria), resources::filter_con); BOOST_FOREACH(const unit &u, *resources::units) { - if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::filter_con)) { + if (ufilt( u )) { LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value() << "\n"; *target_list = target(u.get_location(), value(), target::EXPLICIT); } @@ -259,13 +260,14 @@ void protect_goal::add_targets(std::back_insert_iterator< std::vector< target > std::set items; if (protect_unit_) { + const unit_filter ufilt(vconfig(criteria), resources::filter_con); BOOST_FOREACH(const unit &u, units) { if (protect_only_own_unit_ && u.side() != get_side()) { continue; } //TODO: we will protect hidden units, by not testing for invisibility to current side - if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::filter_con)) { + if (ufilt(u)) { DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected\n"; items.insert(u.get_location()); } diff --git a/src/ai/recruitment/recruitment.cpp b/src/ai/recruitment/recruitment.cpp index 0df705509762..38e24080648b 100644 --- a/src/ai/recruitment/recruitment.cpp +++ b/src/ai/recruitment/recruitment.cpp @@ -252,8 +252,8 @@ void recruitment::execute() { // we'll check if we can do a recall instead of a recruitment. BOOST_FOREACH(const unit_const_ptr & recall, current_team().recall_list()) { // Check if this leader is allowed to recall this unit. - vconfig filter = vconfig(leader->recall_filter()); - if (!unit_filter::matches_filter(filter, *recall, map_location::null_location(), resources::filter_con)) { + const unit_filter ufilt( vconfig(leader->recall_filter()), resources::filter_con); + if (!ufilt(*recall, map_location::null_location())) { continue; } data.recruits.insert(recall->type_id()); @@ -477,8 +477,8 @@ const std::string* recruitment::get_appropriate_recall(const std::string& type, continue; } // Check if this leader is allowed to recall this unit. - vconfig filter = vconfig(leader_data.leader->recall_filter()); - if (!unit_filter::matches_filter(filter, *recall_unit, map_location::null_location(), resources::filter_con)) { + const unit_filter ufilt(vconfig(leader_data.leader->recall_filter()), resources::filter_con); + if (!ufilt(*recall_unit, map_location::null_location())) { LOG_AI_RECRUITMENT << "Refused recall because of filter: " << recall_unit->id() << "\n"; continue; } diff --git a/src/ai/testing/aspect_attacks.cpp b/src/ai/testing/aspect_attacks.cpp index 0571864211dd..0b7741a5bfa2 100644 --- a/src/ai/testing/aspect_attacks.cpp +++ b/src/ai/testing/aspect_attacks.cpp @@ -74,9 +74,10 @@ boost::shared_ptr aspect_attacks::analyze_targets() const unit_map& units_ = *resources::units; std::vector unit_locs; + const unit_filter filt_own(vconfig(filter_own_), resources::filter_con); for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) { if (i->side() == get_side() && i->attacks_left() && !(i->can_recruit() && get_passive_leader())) { - if (!unit_filter::matches_filter(vconfig(filter_own_), *i, i->get_location(), resources::filter_con)) { + if (!filt_own(*i)) { continue; } unit_locs.push_back(i->get_location()); @@ -92,25 +93,26 @@ boost::shared_ptr aspect_attacks::analyze_targets() const unit_stats_cache().clear(); + const unit_filter filt_en(vconfig(filter_enemy_), resources::filter_con); for(unit_map::const_iterator j = units_.begin(); j != units_.end(); ++j) { - // Attack anyone who is on the enemy side, - // and who is not invisible or petrified. - if (current_team().is_enemy(j->side()) && !j->incapacitated() && - !j->invisible(j->get_location())) - { - if (!unit_filter::matches_filter(vconfig(filter_enemy_), *j, j->get_location(), resources::filter_con)) { - continue; - } - map_location adjacent[6]; - get_adjacent_tiles(j->get_location(), adjacent); - attack_analysis analysis; - analysis.target = j->get_location(); - analysis.vulnerability = 0.0; - analysis.support = 0.0; - do_attack_analysis(j->get_location(), srcdst, dstsrc, - fullmove_srcdst, fullmove_dstsrc, enemy_srcdst, enemy_dstsrc, - adjacent,used_locations,unit_locs,*res,analysis, current_team()); + // Attack anyone who is on the enemy side, + // and who is not invisible or petrified. + if (current_team().is_enemy(j->side()) && !j->incapacitated() && + !j->invisible(j->get_location())) + { + if (!filt_en( *j)) { + continue; + } + map_location adjacent[6]; + get_adjacent_tiles(j->get_location(), adjacent); + attack_analysis analysis; + analysis.target = j->get_location(); + analysis.vulnerability = 0.0; + analysis.support = 0.0; + do_attack_analysis(j->get_location(), srcdst, dstsrc, + fullmove_srcdst, fullmove_dstsrc, enemy_srcdst, enemy_dstsrc, + adjacent,used_locations,unit_locs,*res,analysis, current_team()); } } return res; diff --git a/src/game_events/action_wml.cpp b/src/game_events/action_wml.cpp index 0c225c7b1a3e..8eeebd04606d 100644 --- a/src/game_events/action_wml.cpp +++ b/src/game_events/action_wml.cpp @@ -405,8 +405,9 @@ namespace { // Support functions } else if(speaker_str == "second_unit") { speaker = units->find(event_info.loc2); } else if(speaker_str != "narrator") { + const unit_filter ufilt(cfg, resources::filter_con); for(speaker = units->begin(); speaker != units->end(); ++speaker){ - if ( unit_filter::matches_filter(cfg,*speaker, resources::filter_con) ) + if ( ufilt(*speaker) ) break; } } @@ -778,8 +779,9 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg) const vconfig & healers_filter = cfg.child("filter_second"); std::vector healers; if (!healers_filter.null()) { + const unit_filter ufilt(healers_filter, resources::filter_con); BOOST_FOREACH(unit& u, *units) { - if ( unit_filter::matches_filter(healers_filter,u, resources::filter_con) && u.has_ability_type("heals") ) { + if ( ufilt(u) && u.has_ability_type("heals") ) { healers.push_back(&u); } } @@ -794,13 +796,15 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg) const vconfig & healed_filter = cfg.child("filter"); bool only_unit_at_loc1 = healed_filter.null(); bool heal_amount_to_set = true; + + const unit_filter ufilt(healed_filter, resources::filter_con); for(unit_map::unit_iterator u = units->begin(); u != units->end(); ++u) { if (only_unit_at_loc1) { u = units->find(event_info.loc1); if(!u.valid()) return; } - else if ( !unit_filter::matches_filter(healed_filter,*u, resources::filter_con) ) continue; + else if ( !ufilt(*u) ) continue; int heal_amount = u->max_hitpoints() - u->hitpoints(); if(amount.blank() || amount == "full") u->set_hitpoints(u->max_hitpoints()); @@ -857,9 +861,10 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg) if(cfg["fire_event"].to_bool() && secondary_unit) { secondary_unit = false; + const unit_filter ufilt(cfg.child("secondary_unit"), resources::filter_con); for(unit_map::const_unit_iterator unit = resources::units->begin(); unit != resources::units->end(); ++unit) { - if ( unit_filter::matches_filter(cfg.child("secondary_unit"), *unit, resources::filter_con) ) + if ( ufilt( *unit) ) { killer_loc = entity_location(*unit); secondary_unit = true; @@ -873,8 +878,9 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg) //Find all the dead units first, because firing events ruins unit_map iteration std::vector dead_men_walking; + const unit_filter ufilt(cfg, resources::filter_con); BOOST_FOREACH(unit & u, *resources::units){ - if ( unit_filter::matches_filter(cfg,u, resources::filter_con) ) { + if ( ufilt(u) ) { dead_men_walking.push_back(&u); } } @@ -942,13 +948,14 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg) if((cfg_x.empty() || cfg_x == "recall") && (cfg_y.empty() || cfg_y == "recall")) { + const unit_filter ufilt(cfg, resources::filter_con); //remove the unit from the corresponding team's recall list for(std::vector::iterator pi = resources::teams->begin(); pi!=resources::teams->end(); ++pi) { for(std::vector::iterator j = pi->recall_list().begin(); j != pi->recall_list().end();) { //TODO: This block is really messy, cleanup somehow... scoped_recall_unit auto_store("this_unit", pi->save_id(), j - pi->recall_list().begin()); - if (unit_filter::matches_filter(cfg, *(*j), map_location(), resources::filter_con)) { + if (ufilt( *(*j), map_location() )) { j = pi->recall_list().erase(j); } else { ++j; @@ -1415,8 +1422,9 @@ WML_HANDLER_FUNCTION(object, event_info, cfg) map_location loc; if(!filter.null()) { + const unit_filter ufilt(filter, resources::filter_con); BOOST_FOREACH(const unit &u, *resources::units) { - if ( unit_filter::matches_filter(filter,u, resources::filter_con) ) { + if ( ufilt(u) ) { loc = u.get_location(); break; } @@ -1431,7 +1439,7 @@ WML_HANDLER_FUNCTION(object, event_info, cfg) std::string command_type = "then"; - if ( u != resources::units->end() && (filter.null() || unit_filter::matches_filter(filter,*u, resources::filter_con)) ) + if ( u != resources::units->end() && (filter.null() || unit_filter(filter, resources::filter_con).matches(*u)) ) { ///@deprecated This can be removed (and a proper duration=level implemented) after 1.11.2 /// Don't forget to remove it from wmllint too! @@ -1527,7 +1535,7 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) */ temp_config["x"] = "recall"; temp_config["y"] = "recall"; - vconfig unit_filter(temp_config); + vconfig unit_filter_cfg(temp_config); const vconfig & leader_filter = cfg.child("secondary_unit"); for(int index = 0; index < int(resources::teams->size()); ++index) { @@ -1543,10 +1551,12 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) recall_list_manager & avail = (*resources::teams)[index].recall_list(); std::vector leaders = resources::units->find_leaders(index + 1); + const unit_filter ufilt(unit_filter_cfg, resources::filter_con); + const unit_filter lfilt(leader_filter, resources::filter_con); // Note that if leader_filter is null, this correctly gives a null filter that matches all units. for(std::vector::iterator u = avail.begin(); u != avail.end(); ++u) { DBG_NG << "checking unit against filter...\n"; scoped_recall_unit auto_store("this_unit", player_id, u - avail.begin()); - if (unit_filter::matches_filter(unit_filter, *(*u), map_location(), resources::filter_con)) { + if (ufilt(*(*u), map_location())) { DBG_NG << (*u)->id() << " matched the filter...\n"; const unit_ptr to_recruit = *u; const unit* pass_check = to_recruit.get(); @@ -1557,8 +1567,8 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) BOOST_FOREACH(unit_map::const_unit_iterator leader, leaders) { DBG_NG << "...considering " + leader->id() + " as the recalling leader...\n"; map_location loc = cfg_loc; - if ( (leader_filter.null() || unit_filter::matches_filter(leader_filter, *leader, resources::filter_con)) && - unit_filter::matches_filter(vconfig(leader->recall_filter()), *(*u),map_location(), resources::filter_con) ) { + if ( lfilt(*leader) && + unit_filter(vconfig(leader->recall_filter()), resources::filter_con).matches( *(*u),map_location() ) ) { DBG_NG << "...matched the leader filter and is able to recall the unit.\n"; if(!resources::gameboard->map().on_board(loc)) loc = leader->get_location(); @@ -1720,13 +1730,13 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg) std::vector::iterator ti = types.begin(), ti_end = types.end(); // loop to give precedence based on type order + const unit_filter ufilt(filter, resources::filter_con); do { if (has_any_types) { item["type"] = *ti; } - unit_map::iterator itor; BOOST_FOREACH(unit &u, *resources::units) { - if ( unit_filter::matches_filter(filter,u, resources::filter_con) ) { + if ( ufilt(u) ) { u.set_role(cfg["role"]); found = true; break; @@ -1746,6 +1756,7 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg) } // loop to give precedence based on type order std::vector::iterator ti = types.begin(); + const unit_filter ufilt(filter, resources::filter_con); do { if (has_any_types) { item["type"] = *ti; @@ -1763,7 +1774,7 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg) for(size_t i=0; i < pi->recall_list().size(); ++i) { unit_ptr u = pi->recall_list()[i]; scoped_recall_unit auto_store("this_unit", player_id, i); //TODO: Should this not be inside the if? Explain me. - if (unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)) { + if (ufilt( *u, map_location() )) { u->set_role(cfg["role"]); found=true; break; @@ -2286,8 +2297,9 @@ WML_HANDLER_FUNCTION(teleport, event_info, cfg) // Search for a valid unit filter, and if we have one, look for the matching unit const vconfig & filter = cfg.child("filter"); if(!filter.null()) { + const unit_filter ufilt(filter, resources::filter_con); for (u = resources::units->begin(); u != resources::units->end(); ++u){ - if ( unit_filter::matches_filter(filter,*u, resources::filter_con) ) + if ( ufilt(*u) ) break; } } diff --git a/src/game_events/conditional_wml.cpp b/src/game_events/conditional_wml.cpp index 249b94e34031..fe814e55ebd5 100644 --- a/src/game_events/conditional_wml.cpp +++ b/src/game_events/conditional_wml.cpp @@ -74,9 +74,10 @@ namespace { // Support functions std::vector > counts = (*u).has_attribute("count") ? utils::parse_ranges((*u)["count"]) : default_counts; int match_count = 0; + const unit_filter ufilt(*u, resources::filter_con); BOOST_FOREACH(const unit &i, *resources::units) { - if ( i.hitpoints() > 0 && unit_filter::matches_filter(*u,i, resources::filter_con) ) { + if ( i.hitpoints() > 0 && ufilt(i) ) { ++match_count; if(counts == default_counts) { // by default a single match is enough, so avoid extra work @@ -86,6 +87,7 @@ namespace { // Support functions } if ((*u)["search_recall_list"].to_bool()) { + const unit_filter ufilt(*u, resources::filter_con); for(std::vector::iterator team = resources::teams->begin(); team!=resources::teams->end(); ++team) { @@ -97,7 +99,7 @@ namespace { // Support functions break; } scoped_recall_unit auto_store("this_unit", team->save_id(), t); - if ( unit_filter::matches_filter(*u,*team->recall_list()[t], resources::filter_con) ) { + if ( ufilt( *team->recall_list()[t] ) ) { ++match_count; } } diff --git a/src/game_events/entity_location.cpp b/src/game_events/entity_location.cpp index 310b3c3f2bbf..1d8bfb80c8ff 100644 --- a/src/game_events/entity_location.cpp +++ b/src/game_events/entity_location.cpp @@ -20,7 +20,6 @@ #include "global.hpp" #include "entity_location.hpp" -#include "../game_board.hpp" #include "../resources.hpp" #include "../unit.hpp" #include "../unit_filter.hpp" @@ -101,7 +100,7 @@ bool entity_location::matches_unit_filter(const unit_map::const_iterator & un_it // Filter the unit at the filter location (should be the unit's // location if no special filter location was specified). - return unit_filter::matches_filter(filter, *un_it, filter_loc_, resources::filter_con) && + return unit_filter(filter, resources::filter_con).matches(*un_it, filter_loc_) && matches_unit(un_it); } diff --git a/src/pathfind/teleport.cpp b/src/pathfind/teleport.cpp index aef34495cd1b..dda736148143 100644 --- a/src/pathfind/teleport.cpp +++ b/src/pathfind/teleport.cpp @@ -76,7 +76,8 @@ void teleport_group::get_teleport_pair( vconfig filter(cfg_.child_or_empty("filter"), true); vconfig source(cfg_.child_or_empty("source"), true); vconfig target(cfg_.child_or_empty("target"), true); - if (unit_filter::matches_filter(filter, u, loc, resources::filter_con)) { + const unit_filter ufilt(filter, resources::filter_con); + if (ufilt.matches(u, loc)) { scoped_xy_unit teleport_unit("teleport_unit", loc.x, loc.y, *resources::units); diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 4cfb15b7dde9..e3e68371fbb8 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -856,10 +856,11 @@ static int intf_get_units(lua_State *L) lua_newtable(L); int i = 1; unit_map &units = *resources::units; + const unit_filter ufilt(filter, resources::filter_con); // note that if filter is null, this yields a null filter matching everything for (unit_map::const_unit_iterator ui = units.begin(), ui_end = units.end(); ui != ui_end; ++ui) { - if (!filter.null() && !unit_filter::matches_filter(filter, *ui, ui->get_location(), resources::filter_con)) + if (!ufilt(*ui)) continue; new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id()); lua_pushvalue(L, 1); @@ -896,11 +897,11 @@ static int intf_match_unit(lua_State *L) team &t = (*resources::teams)[side - 1]; scoped_recall_unit auto_store("this_unit", t.save_id(), t.recall_list().find_index(u->id())); - lua_pushboolean(L, unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)); + lua_pushboolean(L, unit_filter(filter, resources::filter_con).matches(*u, map_location())); return 1; } - lua_pushboolean(L, unit_filter::matches_filter(filter, *u, u->get_location(), resources::filter_con)); + lua_pushboolean(L, unit_filter(filter, resources::filter_con).matches(*u)); return 1; } @@ -922,6 +923,7 @@ static int intf_get_recall_units(lua_State *L) lua_rawget(L, LUA_REGISTRYINDEX); lua_newtable(L); int i = 1, s = 1; + const unit_filter ufilt(filter, resources::filter_con); BOOST_FOREACH(team &t, *resources::teams) { BOOST_FOREACH(unit_ptr & u, t.recall_list()) @@ -929,7 +931,7 @@ static int intf_get_recall_units(lua_State *L) if (!filter.null()) { scoped_recall_unit auto_store("this_unit", t.save_id(), t.recall_list().find_index(u->id())); - if (!unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)) + if (!ufilt( *u, map_location() )) continue; } new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(s, u->underlying_id()); @@ -2000,11 +2002,12 @@ static int intf_find_cost_map(lua_State *L) else if (!filter.null()) // 1. arg - filter { unit_map &units = *resources::units; + const unit_filter ufilt(filter, resources::filter_con); for (unit_map::const_unit_iterator ui = units.begin(), ui_end = units.end(); ui != ui_end; ++ui) { bool on_map = ui->get_location().valid(); - if (on_map && unit_filter::matches_filter(filter, *ui,ui->get_location(), resources::filter_con)) + if (on_map && ufilt(*ui)) { real_units. push_back(&(*ui)); } diff --git a/src/side_filter.cpp b/src/side_filter.cpp index a40acbd491aa..75074275e121 100644 --- a/src/side_filter.cpp +++ b/src/side_filter.cpp @@ -135,21 +135,22 @@ bool side_filter::match_internal(const team &t) const //Allow filtering on units if(cfg_.has_child("has_unit")) { - const vconfig& unit_filter = cfg_.child("has_unit"); + const vconfig & ufilt_cfg = cfg_.child("has_unit"); + const unit_filter ufilt(ufilt_cfg, fc_, flat_); bool found = false; BOOST_FOREACH(const unit &u, fc_->get_disp_context().units()) { if (u.side() != t.side()) { continue; } - if (unit_filter::matches_filter(unit_filter, u, u.get_location(), fc_, flat_)) { + if (ufilt(u)) { found = true; break; } } - if(!found && unit_filter["search_recall_list"].to_bool(false)) { + if(!found && ufilt_cfg["search_recall_list"].to_bool(false)) { BOOST_FOREACH(const unit_const_ptr & u, t.recall_list()) { scoped_recall_unit this_unit("this_unit", t.save_id(),t.recall_list().find_index(u->id())); - if(unit_filter::matches_filter(unit_filter, *u, u->get_location(), fc_, flat_)) { + if(ufilt(*u)) { found = true; break; } diff --git a/src/terrain_filter.cpp b/src/terrain_filter.cpp index 3a429425ff89..1958f619dcd3 100644 --- a/src/terrain_filter.cpp +++ b/src/terrain_filter.cpp @@ -153,9 +153,9 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x //Allow filtering on unit if(cfg_.has_child("filter")) { - const vconfig& unit_filter = cfg_.child("filter"); + const unit_filter ufilt(vconfig(cfg_.child("filter")), fc_, flat_); const unit_map::const_iterator u = fc_->get_disp_context().units().find(loc); - if (u == fc_->get_disp_context().units().end() || !unit_filter::matches_filter(unit_filter, *u, loc, fc_, flat_)) + if (u == fc_->get_disp_context().units().end() || !ufilt( *u, loc)) return false; } diff --git a/src/unit.cpp b/src/unit.cpp index 444d4a7ad8f1..1cb630cfa4d8 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -1580,7 +1580,7 @@ void unit::add_modification(const std::string& mod_type, const config& mod, bool { // Apply SUF. if (const config &afilter = effect.child("filter")) - if (!unit_filter::matches_filter(vconfig(afilter), *this, loc_, resources::filter_con)) continue; + if (!unit_filter(vconfig(afilter), resources::filter_con).matches(*this, loc_)) continue; const std::string &apply_to = effect["apply_to"]; const std::string &apply_times = effect["times"]; diff --git a/src/unit_abilities.cpp b/src/unit_abilities.cpp index 7a02686f3104..354cdb6a9d56 100644 --- a/src/unit_abilities.cpp +++ b/src/unit_abilities.cpp @@ -297,7 +297,7 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map assert(resources::units && resources::gameboard && resources::teams && resources::tod_manager); if (const config &afilter = cfg.child("filter")) - if ( !unit_filter::matches_filter(vconfig(afilter), *this, loc, resources::filter_con, illuminates) ) + if ( !unit_filter(vconfig(afilter), resources::filter_con, illuminates).matches(*this, loc) ) return false; map_location adjacent[6]; @@ -306,6 +306,7 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map BOOST_FOREACH(const config &i, cfg.child_range("filter_adjacent")) { + const unit_filter ufilt(vconfig(i), resources::filter_con, illuminates); BOOST_FOREACH(const std::string &j, utils::split(i["adjacent"])) { map_location::DIRECTION index = @@ -315,21 +316,22 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map unit_map::const_iterator unit = units.find(adjacent[index]); if (unit == units.end()) return false; - if (!unit_filter::matches_filter(vconfig(i), *unit, unit->get_location(), resources::filter_con, illuminates)) + if (!ufilt( *unit )) return false; } } BOOST_FOREACH(const config &i, cfg.child_range("filter_adjacent_location")) { + terrain_filter adj_filter(vconfig(i), resources::filter_con); + adj_filter.flatten(illuminates); + BOOST_FOREACH(const std::string &j, utils::split(i["adjacent"])) { map_location::DIRECTION index = map_location::parse_direction(j); if (index == map_location::NDIRECTIONS) { continue; } - terrain_filter adj_filter(vconfig(i), resources::filter_con); - adj_filter.flatten(illuminates); if(!adj_filter.match(adjacent[index])) { return false; } @@ -348,12 +350,13 @@ bool unit::ability_affects_adjacent(const std::string& ability, const config& cf assert(dir >=0 && dir <= 5); static const std::string adjacent_names[6] = {"n","ne","se","s","sw","nw"}; + BOOST_FOREACH(const config &i, cfg.child_range("affect_adjacent")) { std::vector dirs = utils::split(i["adjacent"]); if(std::find(dirs.begin(),dirs.end(),adjacent_names[dir]) != dirs.end()) { if (const config &filter = i.child("filter")) { - if ( unit_filter::matches_filter(vconfig(filter), *this, loc, resources::filter_con, illuminates) ) + if ( unit_filter(vconfig(filter), resources::filter_con, illuminates).matches(*this, loc) ) return true; } else return true; @@ -371,7 +374,7 @@ bool unit::ability_affects_self(const std::string& ability,const config& cfg,con const config &filter = cfg.child("filter_self"); bool affect_self = cfg["affect_self"].to_bool(true); if (!filter || !affect_self) return affect_self; - return unit_filter::matches_filter(vconfig(filter), *this, loc, resources::filter_con, ability == "illuminates"); + return unit_filter(vconfig(filter), resources::filter_con, ability == "illuminates").matches(*this, loc); } bool unit::has_ability_type(const std::string& ability) const @@ -794,7 +797,7 @@ namespace { // Helpers for attack_type::special_active() return true; // Check for a unit match. - if ( !un_it.valid() || !unit_filter::matches_filter(vconfig(filter_child), *un_it, loc, resources::filter_con) ) + if ( !un_it.valid() || !unit_filter(vconfig(filter_child), resources::filter_con).matches(*un_it, loc) ) return false; // Check for a weapon match. @@ -884,7 +887,7 @@ bool attack_type::special_active(const config& special, AFFECTS whom, continue; unit_map::const_iterator unit = units.find(adjacent[index]); if ( unit == units.end() || - !unit_filter::matches_filter(vconfig(i), *unit, adjacent[index], resources::filter_con) ) + !unit_filter(vconfig(i), resources::filter_con).matches(*unit, adjacent[index]) ) //TODO: Should this filter get precomputed? return false; } } diff --git a/src/unit_animation.cpp b/src/unit_animation.cpp index 1ccb0a93116b..9e6df5b17c20 100644 --- a/src/unit_animation.cpp +++ b/src/unit_animation.cpp @@ -404,7 +404,7 @@ int unit_animation::matches(const display &disp, const map_location& loc,const m } std::vector::const_iterator myitor; for(myitor = unit_filter_.begin(); myitor != unit_filter_.end(); ++myitor) { - if (!unit_filter::matches_filter(vconfig(*myitor), *my_unit, loc, &disp)) return MATCH_FAIL; + if (!unit_filter(vconfig(*myitor), &disp).matches(*my_unit, loc)) return MATCH_FAIL; //TODO: Precalculate these ++result; } if(!secondary_unit_filter_.empty()) { @@ -413,7 +413,7 @@ int unit_animation::matches(const display &disp, const map_location& loc,const m if (unit->get_location() == second_loc) { std::vector::const_iterator second_itor; for(second_itor = secondary_unit_filter_.begin(); second_itor != secondary_unit_filter_.end(); ++second_itor) { - if (!unit_filter::matches_filter(vconfig(*second_itor), *unit, second_loc, &disp)) return MATCH_FAIL; + if (!unit_filter(vconfig(*second_itor), &disp).matches(*unit, second_loc)) return MATCH_FAIL; //TODO: Precalculate these result++; } diff --git a/src/unit_display.cpp b/src/unit_display.cpp index 1a46437d3a5b..73b3d3fccf06 100644 --- a/src/unit_display.cpp +++ b/src/unit_display.cpp @@ -773,8 +773,9 @@ void wml_animation_internal(unit_animator &animator, const vconfig &cfg, const m // and if we have one, look for the matching unit vconfig filter = cfg.child("filter"); if(!filter.null()) { + const unit_filter ufilt(filter, resources::filter_con); for (u = resources::units->begin(); u != resources::units->end(); ++u) { - if ( unit_filter::matches_filter(filter, *u, resources::filter_con) ) + if ( ufilt(*u) ) break; } } diff --git a/src/unit_filter.cpp b/src/unit_filter.cpp index 492c4f105e97..387ea83e429c 100644 --- a/src/unit_filter.cpp +++ b/src/unit_filter.cpp @@ -32,29 +32,70 @@ #include -namespace { bool internal_matches_filter(const vconfig& filter, const unit & u, const map_location& loc, const filter_context * fc, bool use_flat_tod); } +bool unit_filter::matches(const unit & u) const { + return matches (u, u.get_location()); +} + +//bool unit_filter::matches(const unit & /*u*/, const map_location & /*loc*/) const { +// assert(false && "called match against a pure abstract unit_filter! this indicates a programmer error, this function must be overrided"); +// return false; +//} + +class null_unit_filter_impl : public unit_filter_abstract_impl { +public: + null_unit_filter_impl() {} + virtual bool matches(const unit & /*u*/, const map_location & /*loc*/) const { + return true; + } + + ~null_unit_filter_impl() {} +}; + +class basic_unit_filter_impl : public unit_filter_abstract_impl { +public: + basic_unit_filter_impl(const vconfig & vcfg, const filter_context & fc, bool flat_tod) + : vcfg_(vcfg) + , fc_(fc) + , use_flat_tod_(flat_tod) + {} + virtual bool matches(const unit & u, const map_location & loc) const; + + ~basic_unit_filter_impl() {} +private: + const vconfig & vcfg_; + const filter_context & fc_; + bool use_flat_tod_; -namespace unit_filter { + bool internal_matches_filter(const unit & u, const map_location & loc) const; +}; -bool matches_filter(const vconfig& filter, const unit & u, const filter_context * fc, bool use_flat_tod) -{ return matches_filter(filter, u, u.get_location(), fc, use_flat_tod); } +unit_filter::unit_filter(const vconfig & vcfg, const filter_context * fc, bool flat_tod) +{ + if (!fc) { + assert(false && "attempt to instantiate a unit filter with a null filter context!"); + } + if (vcfg.null()) { + impl_.reset(new null_unit_filter_impl()); + } + impl_.reset(new basic_unit_filter_impl(vcfg, *fc, flat_tod)); + //TODO: Add more efficient implementations for special cases +} -bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, const filter_context * fc, bool use_flat_tod) +bool basic_unit_filter_impl::matches(const unit & u, const map_location& loc) const { bool matches = true; if(loc.valid()) { - assert(fc != NULL); - scoped_xy_unit auto_store("this_unit", loc.x, loc.y, fc->get_disp_context().units()); - matches = internal_matches_filter(cfg, u, loc, fc, use_flat_tod); + scoped_xy_unit auto_store("this_unit", loc.x, loc.y, fc_.get_disp_context().units()); + matches = internal_matches_filter(u, loc); } else { // If loc is invalid, then this is a recall list unit (already been scoped) - matches = internal_matches_filter(cfg, u, loc, fc, use_flat_tod); + matches = internal_matches_filter(u, loc); } // Handle [and], [or], and [not] with in-order precedence - vconfig::all_children_iterator cond = cfg.ordered_begin(); - vconfig::all_children_iterator cond_end = cfg.ordered_end(); + vconfig::all_children_iterator cond = vcfg_.ordered_begin(); + vconfig::all_children_iterator cond_end = vcfg_.ordered_end(); while(cond != cond_end) { @@ -63,15 +104,15 @@ bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, // Handle [and] if(cond_name == "and") { - matches = matches && matches_filter(cond_filter,u, loc, fc, use_flat_tod); + matches = matches && unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); } // Handle [or] else if(cond_name == "or") { - matches = matches || matches_filter(cond_filter,u, loc, fc,use_flat_tod); + matches = matches || unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); } // Handle [not] else if(cond_name == "not") { - matches = matches && !matches_filter(cond_filter,u, loc, fc,use_flat_tod); + matches = matches && !unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); } ++cond; @@ -79,18 +120,14 @@ bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, return matches; } -} //end namespace unit_filter - -namespace { //begin anonymous namespace - -bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, const filter_context * fc, bool use_flat_tod) +bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_location& loc) const { - config::attribute_value cfg_name = cfg["name"]; + config::attribute_value cfg_name = vcfg_["name"]; if (!cfg_name.blank() && cfg_name.str() != u.name()) { return false; } - const config::attribute_value cfg_id = cfg["id"]; + const config::attribute_value cfg_id = vcfg_["id"]; if (!cfg_id.blank()) { const std::string& id = cfg_id; const std::string& this_id = u.id(); @@ -109,35 +146,33 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // Allow 'speaker' as an alternative to id, since people use it so often - config::attribute_value cfg_speaker = cfg["speaker"]; + config::attribute_value cfg_speaker = vcfg_["speaker"]; if (!cfg_speaker.blank() && cfg_speaker.str() != u.id()) { return false; } - if(cfg.has_child("filter_location")) { - assert(fc != NULL); - const vconfig& t_cfg = cfg.child("filter_location"); - terrain_filter t_filter(t_cfg, fc, use_flat_tod); + if(vcfg_.has_child("filter_location")) { + const vconfig& t_cfg = vcfg_.child("filter_location"); + terrain_filter t_filter(t_cfg, &fc_, use_flat_tod_); if(!t_filter.match(loc)) { return false; } } - const vconfig& filter_side = cfg.child("filter_side"); + const vconfig& filter_side = vcfg_.child("filter_side"); if(!filter_side.null()) { - side_filter s_filter(filter_side, fc); + side_filter s_filter(filter_side, &fc_); if(!s_filter.match(u.side())) return false; } // Also allow filtering on location ranges outside of the location filter - config::attribute_value cfg_x = cfg["x"]; - config::attribute_value cfg_y = cfg["y"]; + config::attribute_value cfg_x = vcfg_["x"]; + config::attribute_value cfg_y = vcfg_["y"]; if (!cfg_x.blank() || !cfg_y.blank()){ if(cfg_x == "recall" && cfg_y == "recall") { //locations on the map are considered to not be on a recall list - if ((!fc && loc.valid()) || - (fc && fc->get_disp_context().map().on_board(loc))) + if (fc_.get_disp_context().map().on_board(loc)) { return false; } @@ -149,7 +184,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // The type could be a comma separated list of types - config::attribute_value cfg_type = cfg["type"]; + config::attribute_value cfg_type = vcfg_["type"]; if (!cfg_type.blank()) { const std::string type_ids = cfg_type.str(); @@ -173,7 +208,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // The variation_type could be a comma separated list of types - config::attribute_value cfg_variation_type = cfg["variation"]; + config::attribute_value cfg_variation_type = vcfg_["variation"]; if (!cfg_variation_type.blank()) { const std::string type_ids = cfg_variation_type.str(); @@ -197,7 +232,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // The has_variation_type could be a comma separated list of types - config::attribute_value cfg_has_variation_type = cfg["has_variation"]; + config::attribute_value cfg_has_variation_type = vcfg_["has_variation"]; if (!cfg_has_variation_type.blank()) { const std::string& var_ids = cfg_has_variation_type.str(); @@ -223,7 +258,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_ability = cfg["ability"]; + config::attribute_value cfg_ability = vcfg_["ability"]; if (!cfg_ability.blank()) { std::string ability = cfg_ability; @@ -246,7 +281,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_race = cfg["race"]; + config::attribute_value cfg_race = vcfg_["race"]; if (!cfg_race.blank()) { std::string race = cfg_race; @@ -258,12 +293,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_gender = cfg["gender"]; + config::attribute_value cfg_gender = vcfg_["gender"]; if (!cfg_gender.blank() && string_gender(cfg_gender) != u.gender()) { return false; } - config::attribute_value cfg_side = cfg["side"]; + config::attribute_value cfg_side = vcfg_["side"]; if (!cfg_side.blank() && cfg_side.to_int() != u.side()) { std::string side = cfg_side; if ( side.find(',') == std::string::npos ) { @@ -275,7 +310,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_has_weapon = cfg["has_weapon"]; + config::attribute_value cfg_has_weapon = vcfg_["has_weapon"]; if (!cfg_has_weapon.blank()) { std::string weapon = cfg_has_weapon; bool has_weapon = false; @@ -292,38 +327,38 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_role = cfg["role"]; + config::attribute_value cfg_role = vcfg_["role"]; if (!cfg_role.blank() && cfg_role.str() != u.get_role()) { return false; } - config::attribute_value cfg_ai_special = cfg["ai_special"]; + config::attribute_value cfg_ai_special = vcfg_["ai_special"]; if (!cfg_ai_special.blank() && ((cfg_ai_special.str() == "guardian") != u.get_state(unit::STATE_GUARDIAN))) { return false; } - config::attribute_value cfg_canrecruit = cfg["canrecruit"]; + config::attribute_value cfg_canrecruit = vcfg_["canrecruit"]; if (!cfg_canrecruit.blank() && cfg_canrecruit.to_bool() != u.can_recruit()) { return false; } - config::attribute_value cfg_recall_cost = cfg["recall_cost"]; + config::attribute_value cfg_recall_cost = vcfg_["recall_cost"]; if (!cfg_recall_cost.blank() && cfg_recall_cost.to_int(-1) != u.recall_cost()) { return false; } - config::attribute_value cfg_level = cfg["level"]; + config::attribute_value cfg_level = vcfg_["level"]; if (!cfg_level.blank() && cfg_level.to_int(-1) != u.level()) { return false; } - config::attribute_value cfg_defense = cfg["defense"]; - if (!cfg_defense.blank() && cfg_defense.to_int(-1) != u.defense_modifier(fc->get_disp_context().map().get_terrain(loc))) { + config::attribute_value cfg_defense = vcfg_["defense"]; + if (!cfg_defense.blank() && cfg_defense.to_int(-1) != u.defense_modifier(fc_.get_disp_context().map().get_terrain(loc))) { return false; } - config::attribute_value cfg_movement = cfg["movement_cost"]; - if (!cfg_movement.blank() && cfg_movement.to_int(-1) != u.movement_cost(fc->get_disp_context().map().get_terrain(loc))) { + config::attribute_value cfg_movement = vcfg_["movement_cost"]; + if (!cfg_movement.blank() && cfg_movement.to_int(-1) != u.movement_cost(fc_.get_disp_context().map().get_terrain(loc))) { return false; } @@ -331,7 +366,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat // If a key is in the unit and in the filter, they should match // filter only => not for us // unit only => not filtered - const vconfig::child_list& wmlcfgs = cfg.get_children("filter_wml"); + const vconfig::child_list& wmlcfgs = vcfg_.get_children("filter_wml"); if (!wmlcfgs.empty()) { config unit_cfg; for (unsigned i = 0; i < wmlcfgs.size(); ++i) @@ -355,14 +390,14 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - if (cfg.has_child("filter_vision")) { - const vconfig::child_list& vis_filt = cfg.get_children("filter_vision"); + if (vcfg_.has_child("filter_vision")) { + const vconfig::child_list& vis_filt = vcfg_.get_children("filter_vision"); vconfig::child_list::const_iterator i, i_end = vis_filt.end(); for (i = vis_filt.begin(); i != i_end; ++i) { bool visible = (*i)["visible"].to_bool(true); std::set viewers; // Use standard side filter - side_filter ssf(*i, fc); + side_filter ssf(*i, &fc_); std::vector sides = ssf.get_teams(); viewers.insert(sides.begin(), sides.end()); if (viewers.empty()) { @@ -370,7 +405,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } std::set::const_iterator viewer, viewer_end = viewers.end(); for (viewer = viewers.begin(); viewer != viewer_end; ++viewer) { - bool fogged = fc->get_disp_context().teams()[*viewer - 1].fogged(loc); + bool fogged = fc_.get_disp_context().teams()[*viewer - 1].fogged(loc); bool hiding = u.invisible(loc/*, false(?) */); bool unit_hidden = fogged || hiding; if (visible == unit_hidden) return false; @@ -378,13 +413,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - if (cfg.has_child("filter_adjacent")) { - assert(fc); - const unit_map& units = fc->get_disp_context().units(); + if (vcfg_.has_child("filter_adjacent")) { + const unit_map& units = fc_.get_disp_context().units(); map_location adjacent[6]; get_adjacent_tiles(loc, adjacent); vconfig::child_list::const_iterator i, i_end; - const vconfig::child_list& adj_filt = cfg.get_children("filter_adjacent"); + const vconfig::child_list& adj_filt = vcfg_.get_children("filter_adjacent"); for (i = adj_filt.begin(), i_end = adj_filt.end(); i != i_end; ++i) { int match_count=0; config::attribute_value i_adjacent = (*i)["adjacent"]; @@ -394,12 +428,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat for (j = dirs.begin(); j != j_end; ++j) { unit_map::const_iterator unit_itor = units.find(adjacent[*j]); if (unit_itor == units.end() - || !unit_filter::matches_filter(*i, *unit_itor, unit_itor->get_location(), fc, use_flat_tod)) { + || !unit_filter(*i, &fc_, use_flat_tod_).matches(*unit_itor)) { continue; } config::attribute_value i_is_enemy = (*i)["is_enemy"]; if (i_is_enemy.blank() || i_is_enemy.to_bool() == - fc->get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) { + fc_.get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) { ++match_count; } } @@ -413,7 +447,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_find_in = cfg["find_in"]; + config::attribute_value cfg_find_in = vcfg_["find_in"]; if (!cfg_find_in.blank()) { // Allow filtering by searching a stored variable of units variable_info vi(cfg_find_in, false, variable_info::TYPE_CONTAINER); @@ -429,14 +463,14 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat return false; } } - config::attribute_value cfg_formula = cfg["formula"]; + config::attribute_value cfg_formula = vcfg_["formula"]; if (!cfg_formula.blank()) { if (!u.formula_manager().matches_filter(cfg_formula, loc, u)) { return false; } } - config::attribute_value cfg_lua_function = cfg["lua_function"]; + config::attribute_value cfg_lua_function = vcfg_["lua_function"]; if (!cfg_lua_function.blank()) { bool b = resources::lua_kernel->run_filter(cfg_lua_function.str().c_str(), u); if (!b) return false; @@ -444,5 +478,3 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat return true; } - -} //end anonymous namespace diff --git a/src/unit_filter.hpp b/src/unit_filter.hpp index 1d8d8b757173..06c9e3d82417 100644 --- a/src/unit_filter.hpp +++ b/src/unit_filter.hpp @@ -23,17 +23,37 @@ * these to speed up repeated application of the filter. */ +#include + class filter_context; class unit; class vconfig; struct map_location; -namespace unit_filter { +class unit_filter_abstract_impl { +public: + virtual bool matches(const unit & u, const map_location & loc) const = 0; +}; + +class unit_filter { +public: + unit_filter(const vconfig & cfg, const filter_context * fc, bool use_flat_tod = false); //!< Constructs a unit filter from a config and a context. This function should give the most efficient implementation available. - bool matches_filter(const vconfig& cfg,const unit & u, const map_location& loc, const filter_context * board, bool use_flat_tod=false); + bool matches(const unit & u, const map_location & loc) const { + return impl_->matches(u,loc); + } /// Determine if *this matches @a filter at its current location. /// (Only use for units currently on the map; otherwise use the overload /// that takes a location, possibly with a null location.) - bool matches_filter(const vconfig& filter, const unit & u, const filter_context* board, bool use_flat_tod=false); + bool matches(const unit & u) const; + + bool operator()(const unit & u, const map_location & loc) const { + return matches(u,loc); + } -} + bool operator()(const unit & u) const { + return matches(u); + } +private: + boost::scoped_ptr impl_; +};