Merge branch 'master' into game_variables
Conflicts: src/unit_filter.cpp
This commit is contained in:
commit
c03ac970b0
4 changed files with 268 additions and 138 deletions
23
.travis.yml
23
.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:
|
||||
|
|
|
@ -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<team> & teams() const { return *tm_; }
|
||||
|
||||
private:
|
||||
const unit_map * um_;
|
||||
const gamemap * gm_;
|
||||
const std::vector<team> * 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 {
|
||||
|
|
|
@ -33,7 +33,10 @@
|
|||
#include "variable.hpp" // needed for vconfig, scoped unit
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/ptr_container/ptr_vector.hpp>
|
||||
#include <boost/utility/in_place_factory.hpp> //needed for boost::in_place to initialize optionals
|
||||
|
||||
#include <vector>
|
||||
|
||||
///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 @@ public:
|
|||
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<int> viewers;
|
||||
|
||||
// Use standard side filter
|
||||
side_filter ssf(f, &fc_);
|
||||
std::vector<int> 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<std::pair<int,int> > 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<unit_filter_abstract_impl> cond_children_;
|
||||
boost::ptr_vector<unit_filter> cond_children_;
|
||||
std::vector<conditional::TYPE> cond_child_types_;
|
||||
|
||||
const config::attribute_value cfg_name_;
|
||||
const config::attribute_value cfg_id_;
|
||||
const config::attribute_value cfg_speaker_;
|
||||
boost::scoped_ptr<terrain_filter> cfg_filter_loc_;
|
||||
boost::scoped_ptr<side_filter> 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<std::set<int> > vision_filters_viewers_lists_;
|
||||
std::vector<bool> vision_filters_visible_attr_;
|
||||
|
||||
boost::ptr_vector<unit_filter> filter_adj_filters_;
|
||||
std::vector<boost::optional<bool> > filter_adj_is_enemy_;
|
||||
std::vector<std::vector<map_location::DIRECTION> > filter_adj_dirs_;
|
||||
std::vector<std::vector<std::pair<int,int> > > 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<std::string>& 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<attack_type>& attacks = u.attacks();
|
||||
for(std::vector<attack_type>::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<int> viewers;
|
||||
// Use standard side filter
|
||||
side_filter ssf(*i, &fc_);
|
||||
std::vector<int> sides = ssf.get_teams();
|
||||
viewers.insert(sides.begin(), sides.end());
|
||||
if (viewers.empty()) {
|
||||
return false;
|
||||
}
|
||||
std::set<int>::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<int> & viewers = vision_filters_viewers_lists_[i];
|
||||
if (viewers.empty()) {
|
||||
return false;
|
||||
}
|
||||
std::set<int>::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<map_location::DIRECTION> dirs = !i_adjacent.blank() ?
|
||||
map_location::parse_directions(i_adjacent) : map_location::default_dirs();
|
||||
const std::vector<map_location::DIRECTION> & dirs = filter_adj_dirs_[i];
|
||||
|
||||
std::vector<map_location::DIRECTION>::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<std::pair<int,int> > default_counts = utils::parse_ranges("1-6");
|
||||
config::attribute_value i_count = (*i)["count"];
|
||||
std::vector<std::pair<int,int> > 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue