side_filter.cpp

Go to the documentation of this file.
00001 /* $Id: side_filter.cpp 53671 2012-03-27 19:50:05Z anonymissimus $ */
00002 /*
00003    Copyright (C) 2010 - 2012 by Yurii Chernyi <terraninfo@terraninfo.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #define GETTEXT_DOMAIN "wesnoth-lib"
00017 
00018 #include "global.hpp"
00019 
00020 #include "config.hpp"
00021 #include "foreach.hpp"
00022 #include "log.hpp"
00023 #include "resources.hpp"
00024 #include "side_filter.hpp"
00025 #include "variable.hpp"
00026 #include "team.hpp"
00027 #include "serialization/string_utils.hpp"
00028 
00029 static lg::log_domain log_engine_sf("engine/side_filter");
00030 #define ERR_NG LOG_STREAM(err, log_engine_sf)
00031 
00032 #ifdef _MSC_VER
00033 // This is a workaround for a VC bug; this constructor is never called
00034 // and so we don't care about the warnings this quick fix generates
00035 #pragma warning(push)
00036 #pragma warning(disable:4413)
00037 side_filter::side_filter():
00038     cfg_(vconfig::unconstructed_vconfig()),
00039     flat_(),
00040     side_string_()
00041 {
00042     assert(false);
00043 }
00044 #pragma warning(pop)
00045 #endif
00046 
00047 
00048 side_filter::side_filter(const vconfig& cfg, bool flat_tod) :
00049     cfg_(cfg),
00050     flat_(flat_tod),
00051     side_string_()
00052 {
00053 }
00054 
00055 side_filter::side_filter(const std::string &side_string, bool flat_tod)
00056     : cfg_(vconfig::empty_vconfig()), flat_(flat_tod), side_string_(side_string)
00057 {
00058 }
00059 
00060 std::vector<int> side_filter::get_teams() const
00061 {
00062     //@todo: replace with better implementation
00063     std::vector<int> result;
00064     foreach (const team &t, *resources::teams) {
00065         if (match(t)) {
00066             result.push_back(t.side());
00067         }
00068     }
00069     return result;
00070 }
00071 
00072 static bool check_side_number(const team &t, const std::string &str)
00073 {
00074         std::vector<std::pair<int,int> > ranges = utils::parse_ranges(str);
00075         int side_number = t.side();
00076 
00077         std::vector<std::pair<int,int> >::const_iterator range, range_end = ranges.end();
00078         for (range = ranges.begin(); range != range_end; ++range) {
00079             if(side_number >= range->first && side_number <= range->second) {
00080                 return true;
00081             }
00082         }
00083         return false;
00084 }
00085 
00086 bool side_filter::match_internal(const team &t) const
00087 {
00088     if (cfg_.has_attribute("side_in")) {
00089         if (!check_side_number(t,cfg_["side_in"])) {
00090             return false;
00091         }
00092     }
00093     if (cfg_.has_attribute("side")) {
00094         if (!check_side_number(t,cfg_["side"])) {
00095             return false;
00096         }
00097     }
00098     if (!side_string_.empty()) {
00099         if (!check_side_number(t,side_string_)) {
00100             return false;
00101         }
00102     }
00103 
00104     config::attribute_value cfg_team_name = cfg_["team_name"];
00105     if (!cfg_team_name.blank()) {
00106         const std::string& that_team_name = cfg_team_name;
00107         const std::string& this_team_name = t.team_name();
00108 
00109         if(std::find(this_team_name.begin(), this_team_name.end(), ',') == this_team_name.end()) {
00110             if(this_team_name != that_team_name) return false;
00111         }
00112         else {
00113             const std::vector<std::string>& these_team_names = utils::split(this_team_name);
00114             bool search_futile = true;
00115             foreach(const std::string& this_single_team_name, these_team_names) {
00116                 if(this_single_team_name == that_team_name) {
00117                     search_futile = false;
00118                     break;
00119                 }
00120             }
00121             if(search_futile) return false;
00122         }
00123     }
00124 
00125     //Allow filtering on units
00126     if(cfg_.has_child("has_unit")) {
00127         const vconfig& unit_filter = cfg_.child("has_unit");
00128         bool found = false;
00129         foreach (unit &u, *resources::units) {
00130             if (u.side() != t.side()) {
00131                 continue;
00132             }
00133             if (u.matches_filter(unit_filter, u.get_location(), flat_)) {
00134                 found = true;
00135                 break;
00136             }
00137         }
00138         if(!found && unit_filter["search_recall_list"].to_bool(false)) {
00139             const std::vector<unit>& recall_list = t.recall_list();
00140             foreach(const unit& u, recall_list) {
00141                 scoped_recall_unit this_unit("this_unit", t.save_id(), &u - &recall_list[0]);
00142                 if(u.matches_filter(unit_filter, u.get_location(), flat_)) {
00143                     found = true;
00144                     break;
00145                 }
00146             }
00147         }
00148         if (!found) {
00149             return false;
00150         }
00151     }
00152 
00153     const vconfig& enemy_of = cfg_.child("enemy_of");
00154     if(!enemy_of.null()) {
00155         side_filter s_filter(enemy_of);
00156         const std::vector<int>& teams = s_filter.get_teams();
00157         if(teams.empty()) return false;
00158         foreach(const int side, teams) {
00159             if(!(*resources::teams)[side - 1].is_enemy(t.side()))
00160                 return false;
00161         }
00162     }
00163 
00164     const vconfig& allied_with = cfg_.child("allied_with");
00165     if(!allied_with.null()) {
00166         side_filter s_filter(allied_with);
00167         const std::vector<int>& teams = s_filter.get_teams();
00168         if(teams.empty()) return false;
00169         foreach(const int side, teams) {
00170             if((*resources::teams)[side - 1].is_enemy(t.side()))
00171                 return false;
00172         }
00173     }
00174 
00175     return true;
00176 }
00177 
00178 bool side_filter::match(int side) const
00179 {
00180     return this->match((*resources::teams)[side-1]);
00181 }
00182 
00183 bool side_filter::match(const team& t) const
00184 {
00185     bool matches = match_internal(t);
00186 
00187     //handle [and], [or], and [not] with in-order precedence
00188     vconfig::all_children_iterator cond = cfg_.ordered_begin();
00189     vconfig::all_children_iterator cond_end = cfg_.ordered_end();
00190     while (cond != cond_end) {
00191         const std::string& cond_name = cond.get_key();
00192         const vconfig& cond_cfg = cond.get_child();
00193 
00194         //handle [and]
00195         if(cond_name == "and")
00196         {
00197             matches = matches && side_filter(cond_cfg, flat_).match(t);
00198         }
00199         //handle [or]
00200         else if(cond_name == "or")
00201         {
00202             matches = matches || side_filter(cond_cfg, flat_).match(t);
00203         }
00204         //handle [not]
00205         else if(cond_name == "not")
00206         {
00207             matches = matches && !side_filter(cond_cfg, flat_).match(t);
00208         }
00209             ++cond;
00210     }
00211     return matches;
00212 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:10 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs