The Battle for Wesnoth  1.13.10+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 - 2017 by David White <dave@whitevine.net>
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 
21 
22 #include "config.hpp"
23 #include "game_board.hpp"
24 #include "game_data.hpp"
25 #include "log.hpp"
26 #include "recall_list_manager.hpp"
27 #include "resources.hpp"
30 #include "team.hpp"
31 #include "terrain/filter.hpp"
32 #include "units/unit.hpp"
33 #include "units/filter.hpp"
34 #include "units/map.hpp"
35 #include "variable.hpp"
36 
37 static lg::log_domain log_engine("engine");
38 #define WRN_NG LOG_STREAM(warn, log_engine)
39 
40 
41 // This file is in the game_events namespace.
42 namespace game_events {
43 
44 namespace builtin_conditions {
45  std::vector<std::pair<int,int> > default_counts = utils::parse_ranges("1-99999");
46 
47  bool have_unit(const vconfig& cfg)
48  {
50  return false;
51  }
52  std::vector<std::pair<int,int> > counts = cfg.has_attribute("count")
53  ? utils::parse_ranges(cfg["count"]) : default_counts;
54  int match_count = 0;
55  const unit_filter ufilt(cfg, resources::filter_con);
56  for(const unit &i : resources::gameboard->units()) {
57  if(i.hitpoints() > 0 && ufilt(i)) {
58  ++match_count;
59  if(counts == default_counts) {
60  // by default a single match is enough, so avoid extra work
61  break;
62  }
63  }
64  }
65  if(cfg["search_recall_list"].to_bool()) {
66  for(const team& team : resources::gameboard->teams()) {
67  if(counts == default_counts && match_count) {
68  break;
69  }
70  for(size_t t = 0; t < team.recall_list().size(); ++t) {
71  if(counts == default_counts && match_count) {
72  break;
73  }
74  scoped_recall_unit auto_store("this_unit", team.save_id(), t);
75  if(ufilt(*team.recall_list()[t])) {
76  ++match_count;
77  }
78  }
79  }
80  }
81  return in_ranges(match_count, counts);
82  }
83 
84  bool have_location(const vconfig& cfg)
85  {
86  std::set<map_location> res;
88 
89  std::vector<std::pair<int,int> > counts = cfg.has_attribute("count")
90  ? utils::parse_ranges(cfg["count"]) : default_counts;
91  return in_ranges<int>(res.size(), counts);
92  }
93 
94  bool variable_matches(const vconfig& values)
95  {
96  const std::string name = values["name"];
98 
99 #define TEST_STR_ATTR(name, test) \
100  do { \
101  if (values.has_attribute(name)) { \
102  std::string attr_str = values[name].str(); \
103  std::string str_value = value.str(); \
104  if (!(test)) return false; \
105  } \
106  } while (0)
107 
108 #define TEST_NUM_ATTR(name, test) \
109  do { \
110  if (values.has_attribute(name)) { \
111  double attr_num = values[name].to_double(); \
112  double num_value = value.to_double(); \
113  if (!(test)) return false; \
114  } \
115  } while (0)
116 
117 #define TEST_BOL_ATTR(name, test) \
118  do { \
119  if (values.has_attribute(name)) { \
120  bool attr_bool = values[name].to_bool(); \
121  bool bool_value = value.to_bool(); \
122  if (!(test)) return false; \
123  } \
124  } while (0)
125 
126  TEST_STR_ATTR("equals", str_value == attr_str);
127  TEST_STR_ATTR("not_equals", str_value != attr_str);
128  TEST_NUM_ATTR("numerical_equals", num_value == attr_num);
129  TEST_NUM_ATTR("numerical_not_equals", num_value != attr_num);
130  TEST_NUM_ATTR("greater_than", num_value > attr_num);
131  TEST_NUM_ATTR("less_than", num_value < attr_num);
132  TEST_NUM_ATTR("greater_than_equal_to", num_value >= attr_num);
133  TEST_NUM_ATTR("less_than_equal_to", num_value <= attr_num);
134  TEST_BOL_ATTR("boolean_equals", bool_value == attr_bool);
135  TEST_BOL_ATTR("boolean_not_equals", bool_value != attr_bool);
136  TEST_STR_ATTR("contains", str_value.find(attr_str) != std::string::npos);
137 
138 #undef TEST_STR_ATTR
139 #undef TEST_NUM_ATTR
140 #undef TEST_BOL_ATTR
141  return true;
142  }
143 }
144 
145 namespace { // Support functions
146  bool internal_conditional_passed(const vconfig& cond)
147  {
148  if(cond.has_child("true")) {
149  return true;
150  }
151  if(cond.has_child("false")) {
152  return false;
153  }
154 
156  static const std::set<std::string> skip =
157  {"then", "else", "elseif", "not", "and", "or", "do"};
158 
159  for(vconfig::all_children_iterator it = cond.ordered_begin(); it != cond_end; ++it) {
160  std::string key = it.get_key();
161  bool result = true;
162  if(std::find(skip.begin(), skip.end(), key) == skip.end()) {
163  assert(resources::lua_kernel);
164  result = resources::lua_kernel->run_wml_conditional(key, it.get_child());
165  }
166  if (!result) {
167  return false;
168  }
169  }
170 
171  return true;
172  }
173 
174 } // end anonymous namespace (support functions)
175 
176 
177 bool conditional_passed(const vconfig& cond)
178 {
179  bool matches = internal_conditional_passed(cond);
180 
181  // Handle [and], [or], and [not] with in-order precedence
184  while(cond_i != cond_end)
185  {
186  const std::string& cond_name = cond_i.get_key();
187  const vconfig& cond_filter = cond_i.get_child();
188 
189  // Handle [and]
190  if(cond_name == "and")
191  {
192  matches = matches && conditional_passed(cond_filter);
193  }
194  // Handle [or]
195  else if(cond_name == "or")
196  {
197  matches = matches || conditional_passed(cond_filter);
198  }
199  // Handle [not]
200  else if(cond_name == "not")
201  {
202  matches = matches && !conditional_passed(cond_filter);
203  }
204  ++cond_i;
205  }
206  return matches;
207 }
208 
209 bool matches_special_filter(const config &cfg, const vconfig& filter)
210 {
211  if (!cfg) {
212  WRN_NG << "attempt to filter attack for an event with no attack data." << std::endl;
213  // better to not execute the event (so the problem is more obvious)
214  return false;
215  }
216  // Though it may seem wasteful to put this on the heap, it's necessary.
217  // matches_filter() could potentially call a WFL formula, which would call shared_from_this().
218  auto attack = std::make_shared<const attack_type>(cfg);
219  return attack->matches_filter(filter.get_parsed_config());
220 }
221 
222 } // end namespace game_events
223 
std::vector< char_t > string
#define TEST_STR_ATTR(name, test)
This class represents a single unit of a specific type.
Definition: unit.hpp:101
size_t size() const
Get the number of units on the list.
Variant for storing WML attributes.
vconfig get_child() const
Definition: variable.cpp:421
config get_parsed_config() const
Definition: variable.cpp:140
all_children_iterator ordered_end() const
Definition: variable.cpp:450
bool have_location(const vconfig &cfg)
#define TEST_BOL_ATTR(name, test)
-file sdl_utils.hpp
Definitions for the interface to Wesnoth Markup Language (WML).
game_data * gamedata
Definition: resources.cpp:22
bool have_unit(const vconfig &cfg)
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:44
std::vector< std::pair< int, int > > parse_ranges(const std::string &str)
std::vector< std::pair< int, int > > default_counts
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:67
filter_context * filter_con
Definition: resources.cpp:23
game_board * gameboard
Definition: resources.cpp:20
bool has_child(const std::string &key) const
Returns whether or not *this has a child whose key is key.
Definition: variable.cpp:279
bool variable_matches(const vconfig &values)
static lg::log_domain log_engine("engine")
bool run_wml_conditional(const std::string &, vconfig const &)
Runs a command from an event handler.
Instruction that causes us to skip upcoming instructions.
const std::string & save_id() const
Definition: team.hpp:230
Domain specific events.
Definition: action_wml.cpp:88
Define conditionals for the game's events mechanism, a.k.a.
void get_locations(std::set< map_location > &locs, bool with_border=false) const
gets all locations on the map that match this filter
Definition: filter.hpp:59
bool matches_special_filter(const config &cfg, const vconfig &filter)
#define i
bool conditional_passed(const vconfig &cond)
double t
Definition: astarsearch.cpp:64
bool find(E event, F functor)
Tests whether an event handler is available.
static int cond(LexState *ls)
Definition: lparser.cpp:1177
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
Standard logging facilities (interface).
recall_list_manager & recall_list()
Definition: team.hpp:214
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
#define WRN_NG
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp > > &ranges)
Definition: math.hpp:78
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
#define TEST_NUM_ATTR(name, test)
std::string get_key() const
Definition: variable.cpp:412
unit_map * units
Definition: resources.cpp:34
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition: variable.hpp:99
all_children_iterator ordered_begin() const
In-order iteration over all children.
Definition: variable.cpp:445