The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
conditional_wml.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[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 /**
16  * @file
17  * Implementations of conditional action WML tags.
18  */
19 
20 #include "global.hpp"
21 #include "conditional_wml.hpp"
22 
23 #include "config.hpp"
24 #include "game_board.hpp"
25 #include "game_data.hpp"
26 #include "log.hpp"
27 #include "recall_list_manager.hpp"
28 #include "resources.hpp"
31 #include "team.hpp"
32 #include "terrain/filter.hpp"
33 #include "units/unit.hpp"
34 #include "units/filter.hpp"
35 #include "units/map.hpp"
36 #include "util.hpp"
37 #include "variable.hpp"
38 
39 #include <boost/assign/list_of.hpp>
40 
41 static lg::log_domain log_engine("engine");
42 #define WRN_NG LOG_STREAM(warn, log_engine)
43 
44 
45 // This file is in the game_events namespace.
46 namespace game_events {
47 
48 namespace { // Support functions
49 
50  bool internal_conditional_passed(const vconfig& cond)
51  {
52  const vconfig::child_list& true_keyword = cond.get_children("true");
53  if(!true_keyword.empty()) {
54  return true;
55  }
56 
57  const vconfig::child_list& false_keyword = cond.get_children("false");
58  if(!false_keyword.empty()) {
59  return false;
60  }
61 
62  static std::vector<std::pair<int,int> > default_counts = utils::parse_ranges("1-99999");
63 
64  // If the if statement requires we have a certain unit,
65  // then check for that.
66  const vconfig::child_list& have_unit = cond.get_children("have_unit");
67  for(vconfig::child_list::const_iterator u = have_unit.begin(); u != have_unit.end(); ++u) {
68  if(resources::units == nullptr)
69  return false;
70  std::vector<std::pair<int,int> > counts = (*u).has_attribute("count")
71  ? utils::parse_ranges((*u)["count"]) : default_counts;
72  int match_count = 0;
73  const unit_filter ufilt(*u, resources::filter_con);
74  for (const unit &i : *resources::units)
75  {
76  if ( i.hitpoints() > 0 && ufilt(i) ) {
77  ++match_count;
78  if(counts == default_counts) {
79  // by default a single match is enough, so avoid extra work
80  break;
81  }
82  }
83  }
84  if ((*u)["search_recall_list"].to_bool())
85  {
86  const unit_filter ufilt(*u, resources::filter_con);
88  team!=resources::teams->end(); ++team)
89  {
90  if(counts == default_counts && match_count) {
91  break;
92  }
93  for(size_t t = 0; t < team->recall_list().size(); ++t) {
94  if(counts == default_counts && match_count) {
95  break;
96  }
97  scoped_recall_unit auto_store("this_unit", team->save_id(), t);
98  if ( ufilt( *team->recall_list()[t] ) ) {
99  ++match_count;
100  }
101  }
102  }
103  }
104  if(!in_ranges(match_count, counts)) {
105  return false;
106  }
107  }
108 
109  // If the if statement requires we have a certain location,
110  // then check for that.
111  const vconfig::child_list& have_location = cond.get_children("have_location");
112  for(vconfig::child_list::const_iterator v = have_location.begin(); v != have_location.end(); ++v) {
113  std::set<map_location> res;
115 
116  std::vector<std::pair<int,int> > counts = (*v).has_attribute("count")
117  ? utils::parse_ranges((*v)["count"]) : default_counts;
118  if(!in_ranges<int>(res.size(), counts)) {
119  return false;
120  }
121  }
122 
123  // Check against each variable statement,
124  // to see if the variable matches the conditions or not.
125  const vconfig::child_list& variables = cond.get_children("variable");
126 
127  for (const vconfig &values : variables)
128  {
129  const std::string name = values["name"];
131 
132 #define TEST_STR_ATTR(name, test) do { \
133  if (values.has_attribute(name)) { \
134  std::string attr_str = values[name].str(); \
135  std::string str_value = value.str(); \
136  if (!(test)) return false; \
137  } \
138  } while (0)
139 
140 #define TEST_NUM_ATTR(name, test) do { \
141  if (values.has_attribute(name)) { \
142  double attr_num = values[name].to_double(); \
143  double num_value = value.to_double(); \
144  if (!(test)) return false; \
145  } \
146  } while (0)
147 
148 #define TEST_BOL_ATTR(name, test) do { \
149  if (values.has_attribute(name)) { \
150  bool attr_bool = values[name].to_bool(); \
151  bool bool_value = value.to_bool(); \
152  if (!(test)) return false; \
153  } \
154  } while (0)
155 
156  TEST_STR_ATTR("equals", str_value == attr_str);
157  TEST_STR_ATTR("not_equals", str_value != attr_str);
158  TEST_NUM_ATTR("numerical_equals", num_value == attr_num);
159  TEST_NUM_ATTR("numerical_not_equals", num_value != attr_num);
160  TEST_NUM_ATTR("greater_than", num_value > attr_num);
161  TEST_NUM_ATTR("less_than", num_value < attr_num);
162  TEST_NUM_ATTR("greater_than_equal_to", num_value >= attr_num);
163  TEST_NUM_ATTR("less_than_equal_to", num_value <= attr_num);
164  TEST_BOL_ATTR("boolean_equals", bool_value == attr_bool);
165  TEST_BOL_ATTR("boolean_not_equals", bool_value != attr_bool);
166  TEST_STR_ATTR("contains", str_value.find(attr_str) != std::string::npos);
167 
168 #undef TEST_STR_ATTR
169 #undef TEST_NUM_ATTR
170 #undef TEST_BOL_ATTR
171  }
172 
174  static const boost::container::flat_set<std::string> hard_coded = boost::assign::list_of("true")("false")("have_unit")("have_location")("variable")
175  ("then")("else")("elseif")("not")("and")("or")("do").convert_to_container<boost::container::flat_set<std::string> >();
176 
177  assert(resources::lua_kernel);
178 
179  for (vconfig::all_children_iterator it = cond.ordered_begin(); it != cond_end; ++it) {
180  std::string key = it.get_key();
181  if (std::find(hard_coded.begin(), hard_coded.end(), key) == hard_coded.end()) {
182  bool result = resources::lua_kernel->run_wml_conditional(key, it.get_child());
183  if (!result) {
184  return false;
185  }
186  }
187  }
188 
189  return true;
190  }
191 
192 } // end anonymous namespace (support functions)
193 
194 
196 {
197  bool matches = internal_conditional_passed(cond);
198 
199  // Handle [and], [or], and [not] with in-order precedence
202  while(cond_i != cond_end)
203  {
204  const std::string& cond_name = cond_i.get_key();
205  const vconfig& cond_filter = cond_i.get_child();
206 
207  // Handle [and]
208  if(cond_name == "and")
209  {
210  matches = matches && conditional_passed(cond_filter);
211  }
212  // Handle [or]
213  else if(cond_name == "or")
214  {
215  matches = matches || conditional_passed(cond_filter);
216  }
217  // Handle [not]
218  else if(cond_name == "not")
219  {
220  matches = matches && !conditional_passed(cond_filter);
221  }
222  ++cond_i;
223  }
224  return matches;
225 }
226 
227 bool matches_special_filter(const config &cfg, const vconfig& filter)
228 {
229  if (!cfg) {
230  WRN_NG << "attempt to filter attack for an event with no attack data." << std::endl;
231  // better to not execute the event (so the problem is more obvious)
232  return false;
233  }
234  const attack_type attack(cfg);
235  return attack.matches_filter(filter.get_parsed_config());
236 }
237 
238 } // end namespace game_events
239 
#define TEST_STR_ATTR(name, test)
bool matches_filter(const config &filter) const
Returns whether or not *this matches the given filter.
Definition: unit.hpp:95
size_t size() const
Get the number of units on the list.
vconfig get_child() const
Definition: variable.cpp:374
config get_parsed_config() const
Definition: variable.cpp:131
all_children_iterator ordered_end() const
Definition: variable.cpp:403
#define TEST_BOL_ATTR(name, test)
-file sdl_utils.hpp
bool run_wml_conditional(std::string const &, vconfig const &)
Runs a command from an event handler.
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
game_data * gamedata
Definition: resources.cpp:22
GLboolean GLenum GLenum GLvoid * values
Definition: glew.h:3799
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
GLuint64EXT * result
Definition: glew.h:10727
std::vector< team > * teams
Definition: resources.cpp:29
virtual config::attribute_value get_variable_const(const std::string &varname) const
returns a blank attribute value if varname is no valid variable name.
Definition: game_data.cpp:75
child_list get_children(const std::string &key) const
Definition: variable.cpp:181
filter_context * filter_con
Definition: resources.cpp:23
const GLdouble * v
Definition: glew.h:1359
GLsizei const GLfloat * value
Definition: glew.h:1817
static lg::log_domain log_engine("engine")
Templates and utility-routines for strings and numbers.
const std::string & save_id() const
Definition: team.hpp:236
Domain specific events.
Definition: action_wml.cpp:93
Define conditionals for the game's events mechanism, a.k.a.
GLuint res
Definition: glew.h:9258
void get_locations(std::set< map_location > &locs, bool with_border=false) const
Definition: filter.cpp:495
bool matches_special_filter(const config &cfg, const vconfig &filter)
std::vector< std::pair< int, int > > parse_ranges(std::string const &str)
size_t i
Definition: function.cpp:1057
GLuint const GLchar * name
Definition: glew.h:1782
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:3448
bool conditional_passed(const vconfig &cond)
bool find(E event, F functor)
Tests whether an event handler is available.
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
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
std::vector< vconfig > child_list
Definition: variable.hpp:71
#define WRN_NG
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
#define TEST_NUM_ATTR(name, test)
GLsizei const GLcharARB ** string
Definition: glew.h:4503
std::string get_key() const
Definition: variable.cpp:365
unit_map * units
Definition: resources.cpp:35
all_children_iterator ordered_begin() const
In-order iteration over all children.
Definition: variable.cpp:398
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp > > &ranges)
Definition: util.hpp:195