The Battle for Wesnoth  1.15.10+dev
conditional_wml.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://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-infinity");
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);
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(std::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_or_number(), 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;
87  terrain_filter(cfg, resources::filter_con, false).get_locations(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 
155  static const std::set<std::string> skip
156  {"then", "else", "elseif", "not", "and", "or", "do"};
157 
158  for(const auto& [key, filter] : cond.all_ordered()) {
159  if(std::find(skip.begin(), skip.end(), key) == skip.end()) {
160  assert(resources::lua_kernel);
161  if(!resources::lua_kernel->run_wml_conditional(key, filter)) {
162  return false;
163  }
164  }
165  }
166 
167  return true;
168  }
169 
170 } // end anonymous namespace (support functions)
171 
172 
174 {
175  bool matches = internal_conditional_passed(cond);
176 
177  // Handle [and], [or], and [not] with in-order precedence
178  for(const auto& [key, filter] : cond.all_ordered()) {
179  // Handle [and]
180  if(key == "and") {
181  matches = matches && conditional_passed(filter);
182  }
183  // Handle [or]
184  else if(key == "or") {
185  matches = matches || conditional_passed(filter);
186  }
187  // Handle [not]
188  else if(key == "not") {
189  matches = matches && !conditional_passed(filter);
190  }
191  }
192 
193  return matches;
194 }
195 
196 bool matches_special_filter(const config &cfg, const vconfig& filter)
197 {
198  if (!cfg) {
199  WRN_NG << "attempt to filter attack for an event with no attack data." << std::endl;
200  // better to not execute the event (so the problem is more obvious)
201  return false;
202  }
203  // Though it may seem wasteful to put this on the heap, it's necessary.
204  // matches_filter() could potentially call a WFL formula, which would call shared_from_this().
205  auto attack = std::make_shared<const attack_type>(cfg);
206  return attack->matches_filter(filter.get_parsed_config());
207 }
208 
209 } // end namespace game_events
#define TEST_STR_ATTR(name, test)
This class represents a single unit of a specific type.
Definition: unit.hpp:120
Variant for storing WML attributes.
bool have_location(const vconfig &cfg)
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition: variable.hpp:99
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp >> &ranges)
Definition: math.hpp:86
std::string save_id_or_number() const
Definition: team.hpp:240
#define TEST_BOL_ATTR(name, test)
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 &#39;side&#39; (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
filter_context * filter_con
Definition: resources.cpp:23
game_board * gameboard
Definition: resources.cpp:20
config get_parsed_config() const
Definition: variable.cpp:176
bool variable_matches(const vconfig &values)
static lg::log_domain log_engine("engine")
Domain specific events.
Definition: action_wml.cpp:86
Define conditionals for the game&#39;s events mechanism, a.k.a.
std::size_t i
Definition: function.cpp:934
bool matches_special_filter(const config &cfg, const vconfig &filter)
bool has_child(const std::string &key) const
Returns whether or not *this has a child whose key is key.
Definition: variable.cpp:315
std::string name
Definition: sdl_ttf.cpp:70
std::size_t size() const
Get the number of units on the list.
bool conditional_passed(const vconfig &cond)
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:66
double t
Definition: astarsearch.cpp:64
static int cond(LexState *ls)
Definition: lparser.cpp:1394
A variable-expanding proxy for the config class.
Definition: variable.hpp:44
Standard logging facilities (interface).
recall_list_manager & recall_list()
Definition: team.hpp:223
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
#define WRN_NG
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
#define TEST_NUM_ATTR(name, test)
boost::iterator_range< all_children_iterator > all_ordered() const
Definition: variable.hpp:190