diff --git a/.travis.yml b/.travis.yml index 0aeee77d8445..9aa21f009ad7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,38 +3,41 @@ compiler: - gcc - clang env: - - STRICT_COMPILATION=True - - STRICT_COMPILATION=False + - ALTERNATE_CONFIGURATION=true + - ALTERNATE_CONFIGURATION=false matrix: exclude: - compiler: gcc - env: STRICT_COMPILATION=False + env: ALTERNATE_CONFIGURATION=true before_install: - export TARGETS="wesnoth wesnothd campaignd test" - export WML_TESTS=true - export CPP_TESTS=true - export CHECK_UTF8=true - - if [ "$CXX" = "g++" ]; then export TARGETS="wesnoth test"; fi + - export STRICT_COMPILATION=true + - export EXTRA_FLAGS_RELEASE="-O0" + - export WML_TEST_TIME=40 + - if [ "$ALTERNATE_CONFIGURATION" = true ]; then export STRICT_COMPILATION=false; fi + - if [ "$ALTERNATE_CONFIGURATION" = true ]; then export EXTRA_FLAGS_RELEASE=""; fi + - if [ "$ALTERNATE_CONFIGURATION" = true ]; then export WML_TEST_TIME=20; fi - if [ "$CXX" = "g++" ]; then export WML_TESTS=false; fi -# - if [ "$CXX" = "g++" ]; then export CPP_TESTS=false; fi - if [ "$CXX" = "g++" ]; then export CHECK_UTF8=false; fi - if [ "$CXX" = "g++" ]; then time sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y; fi - - if [ "$CXX" = "g++" ]; then time sudo apt-get update -qq; fi - - if [ "$CXX" = "g++" ]; then time sudo apt-get install g++-4.8; fi - - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8"; fi install: - time sudo apt-get update -qq - time sudo apt-get install -qq libboost-iostreams-dev libboost-program-options-dev libboost-regex-dev libboost-system-dev libboost-test-dev libcairo2-dev libfribidi-dev libpango1.0-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-net1.2-dev libsdl-ttf2.0-dev + - if [ "$CXX" = "g++" ]; then time sudo apt-get install g++-4.8; fi + - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8"; fi - if [ "$CHECK_UTF8" = true ]; then time sudo apt-get install -qq moreutils; fi script: - if [ "$CHECK_UTF8" = true ]; then time ./utils/travis/check_utf8.sh; fi - time if grep -qorHbm1 "^`echo -ne '\xef\xbb\xbf'`" po/ src/ data/ ; then echo "Error, Found a UTF8 BOM:\n"; grep -orHbm1 "^`echo -ne '\xef\xbb\xbf'`" po/ src/ data/ ; exit 1; fi # UTF8 checks are the previous two lines. the second one checks po src data for UTF8 bom, this takes a few seconds. - - scons cxxtool=$CXX --debug=time strict=$STRICT_COMPILATION $TARGETS + - scons cxxtool=$CXX --debug=time build=release extra_flags_release="$EXTRA_FLAGS_RELEASE" strict=$STRICT_COMPILATION $TARGETS - "export DISPLAY=:99.0" - "sh -e /etc/init.d/xvfb start" - if [[ "$CPP_TESTS" = true ]]; then time ./utils/travis/test_wrapper.sh; fi - - if [[ "$WML_TESTS" = true ]]; then time ./run_wml_tests -v -t 20; fi + - if [[ "$WML_TESTS" = true ]]; then time ./run_wml_tests -v -t "$WML_TEST_TIME"; fi after_failure: - if [ -f "errors.log" ]; then echo -e "\n*** \n*\n* Errors reported in wml unit tests, here is errors.log...\n*\n*** \n"; cat errors.log; fi notifications: diff --git a/src/pathfind/teleport.cpp b/src/pathfind/teleport.cpp index d561c0f8ffe3..74a525fcaa10 100644 --- a/src/pathfind/teleport.cpp +++ b/src/pathfind/teleport.cpp @@ -13,6 +13,8 @@ #include "pathfind/teleport.hpp" +#include "display_context.hpp" +#include "filter_context.hpp" #include "game_board.hpp" #include "log.hpp" #include "resources.hpp" @@ -60,28 +62,73 @@ teleport_group::teleport_group(const vconfig& cfg, bool reversed) : cfg_(cfg.get } } +class ignore_units_display_context : public display_context { +public: + ignore_units_display_context(const display_context & dc) + : um_() + , gm_(&dc.map()) + , tm_(&dc.teams()) + { + static unit_map empty_unit_map; + um_ = &empty_unit_map; + } + const unit_map & units() const { return *um_; } + const gamemap & map() const { return *gm_; } + const std::vector & teams() const { return *tm_; } + +private: + const unit_map * um_; + const gamemap * gm_; + const std::vector * tm_; +}; + +class ignore_units_filter_context : public filter_context { +public: + ignore_units_filter_context(const filter_context & fc) + : dc_(fc.get_disp_context()) + , tod_(&fc.get_tod_man()) + {} + + const display_context & get_disp_context() const { return dc_; } + const tod_manager & get_tod_man() const { return *tod_; } + +private: + const ignore_units_display_context dc_; + const tod_manager * tod_; +}; + void teleport_group::get_teleport_pair( teleport_pair& loc_pair , const unit& u - , const bool /*ignore_units*/) const + , const bool ignore_units) const { const map_location &loc = u.get_location(); - static unit_map empty_unit_map; + + const filter_context * fc = resources::filter_con; + assert(fc); + + if (ignore_units) { + fc = new ignore_units_filter_context(*resources::filter_con); + } vconfig filter(cfg_.child_or_empty("filter"), true); vconfig source(cfg_.child_or_empty("source"), true); vconfig target(cfg_.child_or_empty("target"), true); - const unit_filter ufilt(filter, resources::filter_con); + const unit_filter ufilt(filter, resources::filter_con); //Note: Don't use the ignore units filter context here, only for the terrain filters. (That's how it worked before the filter contexts were introduced) if (ufilt.matches(u, loc)) { scoped_xy_unit teleport_unit("teleport_unit", loc.x, loc.y, *resources::units); - terrain_filter source_filter(source, resources::filter_con); + terrain_filter source_filter(source, fc); source_filter.get_locations(reversed_ ? loc_pair.second : loc_pair.first); - terrain_filter target_filter(target, resources::filter_con); + terrain_filter target_filter(target, fc); target_filter.get_locations(reversed_ ? loc_pair.first : loc_pair.second); } + + if (ignore_units) { + delete fc; + } } const std::string& teleport_group::get_teleport_id() const { diff --git a/src/unit_filter.cpp b/src/unit_filter.cpp index c1d5adb5e3b5..76ecdd37ee5f 100644 --- a/src/unit_filter.cpp +++ b/src/unit_filter.cpp @@ -33,7 +33,10 @@ #include "variable.hpp" // needed for vconfig, scoped unit #include +#include #include +#include //needed for boost::in_place to initialize optionals + #include ///Defined out of line to prevent including unit at unit_filter.hpp @@ -46,6 +49,10 @@ bool unit_filter::matches(const unit & u) const { // return false; //} + +/// Forward declare the "construct" method which constructs an appropriate filter impl +static unit_filter_abstract_impl * construct(const vconfig & vcfg, const filter_context & fc, bool flat_tod); + /// Null unit filter is built when the input config is null class null_unit_filter_impl : public unit_filter_abstract_impl { public: @@ -54,7 +61,7 @@ class null_unit_filter_impl : public unit_filter_abstract_impl { return true; } - ~null_unit_filter_impl() {} + virtual ~null_unit_filter_impl() {} }; /// This enum helps to evaluate conditional filters @@ -73,43 +80,159 @@ namespace conditional { 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) + : fc_(fc) , use_flat_tod_(flat_tod) + , cond_children_() + , cond_child_types_() + , cfg_name_(vcfg["name"]) + , cfg_id_(vcfg["id"]) + , cfg_speaker_(vcfg["speaker"]) + , cfg_filter_loc_(vcfg.has_child("filter_location") ? new terrain_filter(vconfig(vcfg.child("filter_location")), &fc_, use_flat_tod_) : NULL) + , cfg_filter_side_(vcfg.has_child("filter_side") ? new side_filter(vconfig(vcfg.child("filter_side")), &fc_) : NULL) //Note that it would be better to use boost optional here but it is apparently not possible to do in an initialiation list using boost::none, because when using ? the types must match, and side_filter is non-copyable + , cfg_x_(vcfg["x"]) + , cfg_y_(vcfg["y"]) + , cfg_type_(vcfg["type"]) + , cfg_variation_type_(vcfg["variation"]) + , cfg_has_variation_type_(vcfg["has_variation"]) + , cfg_ability_(vcfg["ability"]) + , cfg_race_(vcfg["race"]) + , cfg_gender_(vcfg["gender"]) + , cfg_side_(vcfg["side"]) + , cfg_has_weapon_(vcfg["has_weapon"]) + , cfg_role_(vcfg["role"]) + , cfg_ai_special_(vcfg["ai_special"]) + , cfg_canrecruit_(vcfg["canrecruit"]) + , cfg_recall_cost_(vcfg["recall_cost"]) + , cfg_level_(vcfg["level"]) + , cfg_defense_(vcfg["defense"]) + , cfg_movement_(vcfg["movement_cost"]) + , wmlcfgs_(vcfg.get_children("filter_wml")) + , vision_filters_viewers_lists_() + , vision_filters_visible_attr_() + , filter_adj_filters_() + , filter_adj_is_enemy_() + , filter_adj_dirs_() + , filter_adj_counts_() + , cfg_find_in_(vcfg["find_in"]) + , cfg_formula_(vcfg["formula"]) + , cfg_lua_function_(vcfg["lua_function"]) + { // Handle [and], [or], and [not] with in-order precedence - vconfig::all_children_iterator cond = vcfg_.ordered_begin(); - vconfig::all_children_iterator cond_end = vcfg_.ordered_end(); + vconfig::all_children_iterator cond = vcfg.ordered_begin(); + vconfig::all_children_iterator cond_end = vcfg.ordered_end(); while(cond != cond_end) { + const std::string& cond_name = cond.get_key(); + try { - const std::string& cond_name = cond.get_key(); conditional::TYPE type = conditional::string_to_TYPE(cond_name); // throws bad_enum_cast if we don't get a string match with any enum const vconfig& cond_filter = cond.get_child(); - cond_children_.push_back(new basic_unit_filter_impl(cond_filter, fc_, use_flat_tod_)); + cond_children_.push_back(new unit_filter(cond_filter, &fc_, use_flat_tod_)); cond_child_types_.push_back(type); - } catch (bad_enum_cast &) {} //ignore tags that aren't conditionals - + } catch (bad_enum_cast &) { // this means it isn't a conditional filter tag + + //while we are here, process filter_vision tags and filter_adjacent + if (cond_name == "filter_vision") + { + const vconfig& f = cond.get_child(); + vision_filters_visible_attr_.push_back(f["visible"].to_bool(true)); + + std::set viewers; + + // Use standard side filter + side_filter ssf(f, &fc_); + std::vector sides = ssf.get_teams(); + viewers.insert(sides.begin(), sides.end()); + + vision_filters_viewers_lists_.push_back(viewers); + } else if (cond_name == "filter_adjacent") { + const vconfig& f = cond.get_child(); + filter_adj_filters_.push_back(new unit_filter(f, &fc_, use_flat_tod_)); + + config::attribute_value i_adjacent = f["adjacent"]; + filter_adj_dirs_.push_back(!i_adjacent.blank() ? map_location::parse_directions(i_adjacent) : map_location::default_dirs()); + + config::attribute_value i_is_enemy = f["is_enemy"]; + if (i_is_enemy.blank()) { + filter_adj_is_enemy_.push_back(boost::none); + } else { + filter_adj_is_enemy_.push_back(i_is_enemy.to_bool()); + } + static std::vector > default_counts = utils::parse_ranges("1-6"); + config::attribute_value i_count = f["count"]; + filter_adj_counts_.push_back(!i_count.blank() ? utils::parse_ranges(i_count) : default_counts); + } + } ++cond; } } virtual bool matches(const unit & u, const map_location & loc) const; - ~basic_unit_filter_impl() {} + virtual ~basic_unit_filter_impl() {} private: - const vconfig vcfg_; const filter_context & fc_; bool use_flat_tod_; - boost::ptr_vector cond_children_; + boost::ptr_vector cond_children_; std::vector cond_child_types_; + const config::attribute_value cfg_name_; + const config::attribute_value cfg_id_; + const config::attribute_value cfg_speaker_; + boost::scoped_ptr cfg_filter_loc_; + boost::scoped_ptr cfg_filter_side_; + const config::attribute_value cfg_x_; + const config::attribute_value cfg_y_; + const config::attribute_value cfg_type_; + const config::attribute_value cfg_variation_type_; + const config::attribute_value cfg_has_variation_type_; + const config::attribute_value cfg_ability_; + const config::attribute_value cfg_race_; + const config::attribute_value cfg_gender_; + const config::attribute_value cfg_side_; + const config::attribute_value cfg_has_weapon_; + const config::attribute_value cfg_role_; + const config::attribute_value cfg_ai_special_; + const config::attribute_value cfg_canrecruit_; + const config::attribute_value cfg_recall_cost_; + const config::attribute_value cfg_level_; + const config::attribute_value cfg_defense_; + const config::attribute_value cfg_movement_; + + const vconfig::child_list wmlcfgs_; + + std::vector > vision_filters_viewers_lists_; + std::vector vision_filters_visible_attr_; + + boost::ptr_vector filter_adj_filters_; + std::vector > filter_adj_is_enemy_; + std::vector > filter_adj_dirs_; + std::vector > > filter_adj_counts_; + + const config::attribute_value cfg_find_in_; + const config::attribute_value cfg_formula_; + const config::attribute_value cfg_lua_function_; + bool internal_matches_filter(const unit & u, const map_location & loc) const; }; +/** "Factory" method which constructs an appropriate implementation + * + */ + +static unit_filter_abstract_impl * construct(const vconfig & vcfg, const filter_context & fc, bool flat_tod) +{ + if (vcfg.null()) { + return new null_unit_filter_impl(); + } + return new basic_unit_filter_impl(vcfg, fc, flat_tod); + //TODO: Add more efficient implementations for special cases +} + /** Ctor of unit filter * unit_filter::unit_filter acts as a factory, selecting the appropriate implementation class */ @@ -118,11 +241,7 @@ unit_filter::unit_filter(const vconfig & vcfg, const filter_context * fc, bool f 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 + impl_.reset(construct(vcfg, *fc, flat_tod)); } /** Begin implementations of filter impl's @@ -158,14 +277,12 @@ bool basic_unit_filter_impl::matches(const unit & u, const map_location& loc) co bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_location& loc) const { - config::attribute_value cfg_name = vcfg_["name"]; - if (!cfg_name.blank() && cfg_name.str() != u.name()) { + if (!cfg_name_.blank() && cfg_name_.str() != u.name()) { return false; } - const config::attribute_value cfg_id = vcfg_["id"]; - if (!cfg_id.blank()) { - const std::string& id = cfg_id; + if (!cfg_id_.blank()) { + const std::string& id = cfg_id_; const std::string& this_id = u.id(); if (id == this_id) { @@ -182,48 +299,40 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l } // Allow 'speaker' as an alternative to id, since people use it so often - config::attribute_value cfg_speaker = vcfg_["speaker"]; - if (!cfg_speaker.blank() && cfg_speaker.str() != u.id()) { + if (!cfg_speaker_.blank() && cfg_speaker_.str() != u.id()) { return false; } - 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)) { + if(cfg_filter_loc_) { + if(!cfg_filter_loc_->match(loc)) { return false; } } - const vconfig& filter_side = vcfg_.child("filter_side"); - if(!filter_side.null()) { - side_filter s_filter(filter_side, &fc_); - if(!s_filter.match(u.side())) + if(cfg_filter_side_) { + if(!cfg_filter_side_->match(u.side())) return false; } // Also allow filtering on location ranges outside of the location filter - 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") { + 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_.get_disp_context().map().on_board(loc)) { return false; } - } else if(cfg_x.empty() && cfg_y.empty()) { + } else if(cfg_x_.empty() && cfg_y_.empty()) { return false; - } else if(!loc.matches_range(cfg_x, cfg_y)) { + } else if(!loc.matches_range(cfg_x_, cfg_y_)) { return false; } } // The type could be a comma separated list of types - config::attribute_value cfg_type = vcfg_["type"]; - if (!cfg_type.blank()) + if (!cfg_type_.blank()) { - const std::string type_ids = cfg_type.str(); + const std::string type_ids = cfg_type_.str(); const std::string& this_type = u.type_id(); // We only do the full CSV search if we find a comma in there, @@ -244,10 +353,9 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l } // The variation_type could be a comma separated list of types - config::attribute_value cfg_variation_type = vcfg_["variation"]; - if (!cfg_variation_type.blank()) + if (!cfg_variation_type_.blank()) { - const std::string type_ids = cfg_variation_type.str(); + const std::string type_ids = cfg_variation_type_.str(); const std::string& this_type = u.variation(); // We only do the full CSV search if we find a comma in there, @@ -268,10 +376,9 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l } // The has_variation_type could be a comma separated list of types - config::attribute_value cfg_has_variation_type = vcfg_["has_variation"]; - if (!cfg_has_variation_type.blank()) + if (!cfg_has_variation_type_.blank()) { - const std::string& var_ids = cfg_has_variation_type.str(); + const std::string& var_ids = cfg_has_variation_type_.str(); const std::string& this_var = u.variation(); if ( var_ids == this_var ) { @@ -294,10 +401,9 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l } } - config::attribute_value cfg_ability = vcfg_["ability"]; - if (!cfg_ability.blank()) + if (!cfg_ability_.blank()) { - std::string ability = cfg_ability; + std::string ability = cfg_ability_; if(u.has_ability_by_id(ability)) { // pass } else if ( ability.find(',') != std::string::npos ) { @@ -317,9 +423,8 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l } } - config::attribute_value cfg_race = vcfg_["race"]; - if (!cfg_race.blank()) { - std::string race = cfg_race; + if (!cfg_race_.blank()) { + std::string race = cfg_race_; if(race != u.race()->id()) { const std::vector& vals = utils::split(race); @@ -329,14 +434,12 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l } } - config::attribute_value cfg_gender = vcfg_["gender"]; - if (!cfg_gender.blank() && string_gender(cfg_gender) != u.gender()) { + if (!cfg_gender_.blank() && string_gender(cfg_gender_) != u.gender()) { return false; } - config::attribute_value cfg_side = vcfg_["side"]; - if (!cfg_side.blank() && cfg_side.to_int() != u.side()) { - std::string side = cfg_side; + if (!cfg_side_.blank() && cfg_side_.to_int() != u.side()) { + std::string side = cfg_side_; if ( side.find(',') == std::string::npos ) { return false; } @@ -346,9 +449,8 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l } } - config::attribute_value cfg_has_weapon = vcfg_["has_weapon"]; - if (!cfg_has_weapon.blank()) { - std::string weapon = cfg_has_weapon; + if (!cfg_has_weapon_.blank()) { + std::string weapon = cfg_has_weapon_; bool has_weapon = false; const std::vector& attacks = u.attacks(); for(std::vector::const_iterator i = attacks.begin(); @@ -363,38 +465,31 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l } } - config::attribute_value cfg_role = vcfg_["role"]; - if (!cfg_role.blank() && cfg_role.str() != u.get_role()) { + if (!cfg_role_.blank() && cfg_role_.str() != u.get_role()) { return false; } - 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))) { + if (!cfg_ai_special_.blank() && ((cfg_ai_special_.str() == "guardian") != u.get_state(unit::STATE_GUARDIAN))) { return false; } - config::attribute_value cfg_canrecruit = vcfg_["canrecruit"]; - if (!cfg_canrecruit.blank() && cfg_canrecruit.to_bool() != u.can_recruit()) { + if (!cfg_canrecruit_.blank() && cfg_canrecruit_.to_bool() != u.can_recruit()) { return false; } - config::attribute_value cfg_recall_cost = vcfg_["recall_cost"]; - if (!cfg_recall_cost.blank() && cfg_recall_cost.to_int(-1) != u.recall_cost()) { + if (!cfg_recall_cost_.blank() && cfg_recall_cost_.to_int(-1) != u.recall_cost()) { return false; } - config::attribute_value cfg_level = vcfg_["level"]; - if (!cfg_level.blank() && cfg_level.to_int(-1) != u.level()) { + if (!cfg_level_.blank() && cfg_level_.to_int(-1) != u.level()) { return false; } - 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))) { + 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 = vcfg_["movement_cost"]; - if (!cfg_movement.blank() && cfg_movement.to_int(-1) != u.movement_cost(fc_.get_disp_context().map().get_terrain(loc))) { + if (!cfg_movement_.blank() && cfg_movement_.to_int(-1) != u.movement_cost(fc_.get_disp_context().map().get_terrain(loc))) { return false; } @@ -402,12 +497,11 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l // 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 = vcfg_.get_children("filter_wml"); - if (!wmlcfgs.empty()) { + if (!wmlcfgs_.empty()) { config unit_cfg; - for (unsigned i = 0; i < wmlcfgs.size(); ++i) + for (unsigned i = 0; i < wmlcfgs_.size(); ++i) { - config fwml = wmlcfgs[i].get_parsed_config(); + config fwml = wmlcfgs_[i].get_parsed_config(); /* Check if the filter only cares about variables. If so, no need to serialize the whole unit. */ config::const_attr_itors ai = fwml.attribute_range(); @@ -426,69 +520,56 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l } } - 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_); - std::vector sides = ssf.get_teams(); - viewers.insert(sides.begin(), sides.end()); - if (viewers.empty()) { - return false; - } - 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 hiding = u.invisible(loc/*, false(?) */); - bool unit_hidden = fogged || hiding; - if (visible == unit_hidden) return false; - } + assert(vision_filters_viewers_lists_.size() == vision_filters_visible_attr_.size()); + for (size_t i = 0; i < vision_filters_viewers_lists_.size(); i++) { + const std::set & viewers = vision_filters_viewers_lists_[i]; + if (viewers.empty()) { + return false; + } + 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 hiding = u.invisible(loc/*, false(?) */); + bool unit_hidden = fogged || hiding; + if (vision_filters_visible_attr_[i] == unit_hidden) return false; } } - if (vcfg_.has_child("filter_adjacent")) { + assert(filter_adj_filters_.size() == filter_adj_is_enemy_.size()); + assert(filter_adj_filters_.size() == filter_adj_dirs_.size()); + assert(filter_adj_filters_.size() == filter_adj_counts_.size()); + if (filter_adj_filters_.size() > 0) { 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 = vcfg_.get_children("filter_adjacent"); - for (i = adj_filt.begin(), i_end = adj_filt.end(); i != i_end; ++i) { + + for (size_t i = 0; i < filter_adj_filters_.size(); i++) { int match_count=0; - config::attribute_value i_adjacent = (*i)["adjacent"]; - std::vector dirs = !i_adjacent.blank() ? - map_location::parse_directions(i_adjacent) : map_location::default_dirs(); + const std::vector & dirs = filter_adj_dirs_[i]; + std::vector::const_iterator j, j_end = dirs.end(); 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(*i, &fc_, use_flat_tod_).matches(*unit_itor)) { + if (unit_itor == units.end() || !filter_adj_filters_[i](*unit_itor)) { continue; } - config::attribute_value i_is_enemy = (*i)["is_enemy"]; - if (i_is_enemy.blank() || i_is_enemy.to_bool() == + if (!filter_adj_is_enemy_[i] || *filter_adj_is_enemy_[i] == fc_.get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) { ++match_count; } } - static std::vector > default_counts = utils::parse_ranges("1-6"); - config::attribute_value i_count = (*i)["count"]; - std::vector > counts = !i_count.blank() - ? utils::parse_ranges(i_count) : default_counts; - if(!in_ranges(match_count, counts)) { + + if(!in_ranges(match_count, filter_adj_counts_[i])) { return false; } } } - config::attribute_value cfg_find_in = vcfg_["find_in"]; - if (!cfg_find_in.blank()) { + if (!cfg_find_in_.blank()) { // Allow filtering by searching a stored variable of units try { - variable_access_const vi = resources::gamedata->get_variable_access_read(cfg_find_in); + variable_access_const vi = resources::gamedata->get_variable_access_read(cfg_find_in_); bool found_id = false; BOOST_FOREACH(const config& c, vi.as_array()) { @@ -505,16 +586,14 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l return false; } } - config::attribute_value cfg_formula = vcfg_["formula"]; - if (!cfg_formula.blank()) { - if (!u.formula_manager().matches_filter(cfg_formula, loc, u)) { + if (!cfg_formula_.blank()) { + if (!u.formula_manager().matches_filter(cfg_formula_, loc, u)) { return false; } } - 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 (!cfg_lua_function_.blank()) { + bool b = resources::lua_kernel->run_filter(cfg_lua_function_.str().c_str(), u); if (!b) return false; } diff --git a/src/unit_filter.hpp b/src/unit_filter.hpp index 06c9e3d82417..08f366962fc8 100644 --- a/src/unit_filter.hpp +++ b/src/unit_filter.hpp @@ -33,6 +33,7 @@ struct map_location; class unit_filter_abstract_impl { public: virtual bool matches(const unit & u, const map_location & loc) const = 0; + virtual ~unit_filter_abstract_impl() {} }; class unit_filter {