The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
side_filter.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2016 by Yurii Chernyi <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "global.hpp"
18 
19 #include "config.hpp"
20 #include "display_context.hpp"
21 #include "filter_context.hpp"
22 #include "log.hpp"
23 #include "recall_list_manager.hpp"
24 #include "side_filter.hpp"
25 #include "variable.hpp"
26 #include "team.hpp"
28 #include "play_controller.hpp"
29 #include "resources.hpp"
30 #include "synced_context.hpp"
31 #include "units/unit.hpp"
32 #include "units/filter.hpp"
33 #include "units/map.hpp"
34 #include "variable.hpp"
35 #include "formula/callable_objects.hpp"
36 #include "formula/formula.hpp"
37 
38 static lg::log_domain log_engine_sf("engine/side_filter");
39 #define ERR_NG LOG_STREAM(err, log_engine_sf)
40 
41 #ifdef _MSC_VER
42 // This is a workaround for a VC bug; this constructor is never called
43 // and so we don't care about the warnings this quick fix generates
44 #pragma warning(push)
45 #pragma warning(disable:4413)
47  : cfg_(vconfig::unconstructed_vconfig())
48  , flat_()
49  , side_string_()
50  , fc_(nullptr)
51 {
52  assert(false);
53 }
54 #pragma warning(pop)
55 #endif
56 
58 
59 side_filter::side_filter(const vconfig& cfg, const filter_context * fc, bool flat_tod)
60  : cfg_(cfg)
61  , flat_(flat_tod)
62  , side_string_()
63  , fc_(fc)
64 {
65 }
66 
67 side_filter::side_filter(const std::string &side_string, const filter_context * fc, bool flat_tod)
68  : cfg_(vconfig::empty_vconfig()), flat_(flat_tod), side_string_(side_string), fc_(fc)
69 {
70 }
71 
72 std::vector<int> side_filter::get_teams() const
73 {
74  assert(fc_);
75  //@todo: replace with better implementation
76  std::vector<int> result;
77  for(const team &t : fc_->get_disp_context().teams()) {
78  if (match(t)) {
79  result.push_back(t.side());
80  }
81  }
82  return result;
83 }
84 
85 static bool check_side_number(const team &t, const std::string &str)
86 {
87  std::vector<std::pair<int,int> > ranges = utils::parse_ranges(str);
88  int side_number = t.side();
89 
90  std::vector<std::pair<int,int> >::const_iterator range, range_end = ranges.end();
91  for (range = ranges.begin(); range != range_end; ++range) {
92  if(side_number >= range->first && side_number <= range->second) {
93  return true;
94  }
95  }
96  return false;
97 }
98 
100 {
101  assert(fc_);
102 
103  if (cfg_.has_attribute("side_in")) {
104  if (!check_side_number(t,cfg_["side_in"])) {
105  return false;
106  }
107  }
108  if (cfg_.has_attribute("side")) {
109  if (!check_side_number(t,cfg_["side"])) {
110  return false;
111  }
112  }
113  if (!side_string_.empty()) {
115  return false;
116  }
117  }
118 
119  config::attribute_value cfg_team_name = cfg_["team_name"];
120  if (!cfg_team_name.blank()) {
121  const std::string& that_team_name = cfg_team_name;
122  const std::string& this_team_name = t.team_name();
123 
124  if(std::find(this_team_name.begin(), this_team_name.end(), ',') == this_team_name.end()) {
125  if(this_team_name != that_team_name) return false;
126  }
127  else {
128  const std::vector<std::string>& these_team_names = utils::split(this_team_name);
129  bool search_futile = true;
130  for(const std::string& this_single_team_name : these_team_names) {
131  if(this_single_team_name == that_team_name) {
132  search_futile = false;
133  break;
134  }
135  }
136  if(search_futile) return false;
137  }
138  }
139 
140  //Allow filtering on units
141  if(cfg_.has_child("has_unit")) {
142  const vconfig & ufilt_cfg = cfg_.child("has_unit");
143  if (!ufilter_)
144  ufilter_.reset(new unit_filter(ufilt_cfg, fc_, flat_));
145  bool found = false;
146  for(const unit &u : fc_->get_disp_context().units()) {
147  if (u.side() != t.side()) {
148  continue;
149  }
150  if (ufilter_->matches(u)) {
151  found = true;
152  break;
153  }
154  }
155  if(!found && ufilt_cfg["search_recall_list"].to_bool(false)) {
156  for(const unit_const_ptr & u : t.recall_list()) {
157  scoped_recall_unit this_unit("this_unit", t.save_id(),t.recall_list().find_index(u->id()));
158  if(ufilter_->matches(*u)) {
159  found = true;
160  break;
161  }
162  }
163  }
164  if (!found) {
165  return false;
166  }
167  }
168 
169  const vconfig& enemy_of = cfg_.child("enemy_of");
170  if(!enemy_of.null()) {
171  if (!enemy_filter_)
172  enemy_filter_.reset(new side_filter(enemy_of, fc_));
173  const std::vector<int>& teams = enemy_filter_->get_teams();
174  if(teams.empty()) return false;
175  for(const int side : teams) {
176  if(!(fc_->get_disp_context().teams())[side - 1].is_enemy(t.side()))
177  return false;
178  }
179  }
180 
181  const vconfig& allied_with = cfg_.child("allied_with");
182  if(!allied_with.null()) {
183  if (!allied_filter_)
184  allied_filter_.reset(new side_filter(allied_with, fc_));
185  const std::vector<int>& teams = allied_filter_->get_teams();
186  if(teams.empty()) return false;
187  for(const int side : teams) {
188  if((fc_->get_disp_context().teams())[side - 1].is_enemy(t.side()))
189  return false;
190  }
191  }
192 
193  const vconfig& has_enemy = cfg_.child("has_enemy");
194  if(!has_enemy.null()) {
195  if (!has_enemy_filter_)
196  has_enemy_filter_.reset(new side_filter(has_enemy, fc_));
197  const std::vector<int>& teams = has_enemy_filter_->get_teams();
198  bool found = false;
199  for(const int side : teams) {
200  if((fc_->get_disp_context().teams())[side - 1].is_enemy(t.side()))
201  {
202  found = true;
203  break;
204  }
205  }
206  if (!found) return false;
207  }
208 
209  const vconfig& has_ally = cfg_.child("has_ally");
210  if(!has_ally.null()) {
211  if (!has_ally_filter_)
212  has_ally_filter_.reset(new side_filter(has_ally, fc_));
213  const std::vector<int>& teams = has_ally_filter_->get_teams();
214  bool found = false;
215  for(const int side : teams) {
216  if(!(fc_->get_disp_context().teams())[side - 1].is_enemy(t.side()))
217  {
218  found = true;
219  break;
220  }
221  }
222  if (!found) return false;
223  }
224 
225 
226  const config::attribute_value cfg_controller = cfg_["controller"];
227  if (!cfg_controller.blank())
228  {
229  if (resources::controller->is_networked_mp() && synced_context::is_synced()) {
230  ERR_NG << "ignoring controller= in SSF due to danger of OOS errors" << std::endl;
231  }
232  else {
233  bool found = false;
234  for(const std::string& controller : utils::split(cfg_controller))
235  {
236  if(t.controller().to_string() == controller) {
237  found = true;
238  }
239  }
240  if(!found) {
241  return false;
242  }
243  }
244  }
245 
246  if (cfg_.has_attribute("formula")) {
247  try {
248  const team_callable callable(t);
249  const game_logic::formula form(cfg_["formula"]);
250  if(!form.evaluate(callable).as_bool()) {
251  return false;
252  }
253  return true;
254  } catch(game_logic::formula_error& e) {
255  lg::wml_error() << "Formula error in side filter: " << e.type << " at " << e.filename << ':' << e.line << ")\n";
256  // Formulae with syntax errors match nothing
257  return false;
258  }
259  }
260 
261  return true;
262 }
263 
264 bool side_filter::match(int side) const
265 {
266  assert(fc_);
267  return this->match((fc_->get_disp_context().teams())[side-1]);
268 }
269 
270 bool side_filter::match(const team& t) const
271 {
272  bool matches = match_internal(t);
273 
274  //handle [and], [or], and [not] with in-order precedence
277  while (cond != cond_end) {
278  const std::string& cond_name = cond.get_key();
279  const vconfig& cond_cfg = cond.get_child();
280 
281  //handle [and]
282  if(cond_name == "and")
283  {
284  matches = matches && side_filter(cond_cfg, fc_, flat_).match(t);
285  }
286  //handle [or]
287  else if(cond_name == "or")
288  {
289  matches = matches || side_filter(cond_cfg, fc_, flat_).match(t);
290  }
291  //handle [not]
292  else if(cond_name == "not")
293  {
294  matches = matches && !side_filter(cond_cfg, fc_, flat_).match(t);
295  }
296  ++cond;
297  }
298  return matches;
299 }
std::vector< int > get_teams() const
Definition: side_filter.cpp:72
play_controller * controller
Definition: resources.cpp:21
static lg::log_domain log_engine_sf("engine/side_filter")
virtual const display_context & get_disp_context() const =0
Definition: unit.hpp:95
boost::scoped_ptr< side_filter > enemy_filter_
Definition: side_filter.hpp:67
const filter_context * fc_
The filter context for this filter. It should be a pointer because otherwise the default ctor doesn't...
Definition: side_filter.hpp:63
bool match(const team &t) const
GLenum GLint * range
Definition: glew.h:3025
vconfig get_child() const
Definition: variable.cpp:374
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
Definition: variable.cpp:243
all_children_iterator ordered_end() const
Definition: variable.cpp:403
bool as_bool() const
Definition: variant.cpp:580
-file sdl_utils.hpp
GLdouble GLdouble t
Definition: glew.h:1366
Definitions for the interface to Wesnoth Markup Language (WML).
Variant for storing WML attributes.
Definition: config.hpp:223
bool blank() const
Tests for an attribute that was never set.
Definition: config.cpp:367
static std::vector< team > *& teams
Definition: team.cpp:50
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
bool null() const
Definition: variable.hpp:66
GLuint64EXT * result
Definition: glew.h:10727
#define ERR_NG
Definition: side_filter.cpp:39
bool has_child(const std::string &key) const
Returns whether or not *this has a child whose key is key.
Definition: variable.cpp:270
const std::string & team_name() const
Definition: team.hpp:297
virtual const unit_map & units() const =0
const std::string & save_id() const
Definition: team.hpp:236
std::string side_string_
Definition: side_filter.hpp:61
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:31
boost::scoped_ptr< side_filter > allied_filter_
Definition: side_filter.hpp:66
virtual const std::vector< team > & teams() const =0
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:262
boost::scoped_ptr< unit_filter > ufilter_
Definition: side_filter.hpp:65
std::vector< std::pair< int, int > > parse_ranges(std::string const &str)
bool match_internal(const team &t) const
Definition: side_filter.cpp:99
const vconfig cfg_
Definition: side_filter.hpp:58
boost::scoped_ptr< side_filter > has_ally_filter_
Definition: side_filter.hpp:68
int side() const
Definition: team.hpp:193
CONTROLLER controller() const
Definition: team.hpp:256
size_t find_index(const std::string &unit_id) const
Find the index of a unit by its id.
boost::scoped_ptr< side_filter > has_enemy_filter_
Definition: side_filter.hpp:69
bool find(E event, F functor)
Tests whether an event handler is available.
static bool check_side_number(const team &t, const std::string &str)
Definition: side_filter.cpp:85
static int cond(LexState *ls)
Definition: lparser.cpp:1168
A variable-expanding proxy for the config class.
Definition: variable.hpp:36
Standard logging facilities (interface).
recall_list_manager & recall_list()
Definition: team.hpp:220
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
#define e
int side_number
Definition: game_info.hpp:44
static bool is_synced()
GLsizei const GLcharARB ** string
Definition: glew.h:4503
std::string get_key() const
Definition: variable.cpp:365
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition: variable.hpp:92
all_children_iterator ordered_begin() const
In-order iteration over all children.
Definition: variable.cpp:398
side_filter(const std::string &side_string, const filter_context *fc, bool flat_tod=false)
Definition: side_filter.cpp:67