The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
conditional_wml.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 2025
3 by David White <dave@whitevine.net>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16/**
17 * @file
18 * Implementations of conditional action WML tags.
19 */
20
22
23#include "config.hpp"
24#include "game_board.hpp"
25#include "game_data.hpp"
26#include "log.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 "utils/general.hpp"
37#include "variable.hpp"
38
39static lg::log_domain log_engine("engine");
40#define WRN_NG LOG_STREAM(warn, log_engine)
41
42static lg::log_domain log_wml("wml");
43#define ERR_WML LOG_STREAM(err, log_wml)
44
45
46// This file is in the game_events namespace.
47namespace game_events {
48
49namespace builtin_conditions {
50 std::vector<std::pair<int,int>> default_counts = utils::parse_ranges_unsigned("1-infinity");
51
52 bool have_unit(const vconfig& cfg)
53 {
55 return false;
56 }
57 std::vector<std::pair<int,int>> counts = cfg.has_attribute("count")
59 int match_count = 0;
60 const unit_filter ufilt(cfg);
61 for(const unit &i : resources::gameboard->units()) {
62 if(i.hitpoints() > 0 && ufilt(i)) {
63 ++match_count;
64 if(counts == default_counts) {
65 // by default a single match is enough, so avoid extra work
66 break;
67 }
68 }
69 }
70 if(cfg["search_recall_list"].to_bool()) {
71 for(const team& team : resources::gameboard->teams()) {
72 if(counts == default_counts && match_count) {
73 break;
74 }
75 for(std::size_t t = 0; t < team.recall_list().size(); ++t) {
76 if(counts == default_counts && match_count) {
77 break;
78 }
79 scoped_recall_unit auto_store("this_unit", team.save_id_or_number(), t);
80 if(ufilt(*team.recall_list()[t])) {
81 ++match_count;
82 }
83 }
84 }
85 }
86 return in_ranges(match_count, counts);
87 }
88
90 {
91 std::set<map_location> res;
92 terrain_filter(cfg, resources::filter_con, false).get_locations(res);
93
94 std::vector<std::pair<int,int>> counts = cfg.has_attribute("count")
96 return in_ranges<int>(res.size(), counts);
97 }
98
99 bool variable_matches(const vconfig& values)
100 {
101 if(values["name"].blank()) {
102 lg::log_to_chat() << "[variable] with missing name=\n";
103 ERR_WML << "[variable] with missing name=";
104 return true;
105 }
106 const std::string name = values["name"];
108
109 if(auto n = values.get_config().attribute_count(); n > 2) {
110 lg::log_to_chat() << "[variable] name='" << name << "' found with multiple comparison attributes\n";
111 ERR_WML << "[variable] name='" << name << "' found with multiple comparison attributes";
112 } else if(n < 2) {
113 lg::log_to_chat() << "[variable] name='" << name << "' found with no comparison attribute\n";
114 ERR_WML << "[variable] name='" << name << "' found with no comparison attribute";
115 }
116
117#define TEST_STR_ATTR(name, test) \
118 do { \
119 if (values.has_attribute(name)) { \
120 std::string attr_str = values[name].str(); \
121 std::string str_value = value.str(); \
122 return (test); \
123 } \
124 } while (0)
125
126#define TEST_NUM_ATTR(name, test) \
127 do { \
128 if (values.has_attribute(name)) { \
129 double attr_num = values[name].to_double(); \
130 double num_value = value.to_double(); \
131 return (test); \
132 } \
133 } while (0)
134
135#define TEST_BOL_ATTR(name, test) \
136 do { \
137 if (values.has_attribute(name)) { \
138 bool attr_bool = values[name].to_bool(); \
139 bool bool_value = value.to_bool(); \
140 return (test); \
141 } \
142 } while (0)
143
144 TEST_STR_ATTR("equals", str_value == attr_str);
145 TEST_STR_ATTR("not_equals", str_value != attr_str);
146 TEST_NUM_ATTR("numerical_equals", num_value == attr_num);
147 TEST_NUM_ATTR("numerical_not_equals", num_value != attr_num);
148 TEST_NUM_ATTR("greater_than", num_value > attr_num);
149 TEST_NUM_ATTR("less_than", num_value < attr_num);
150 TEST_NUM_ATTR("greater_than_equal_to", num_value >= attr_num);
151 TEST_NUM_ATTR("less_than_equal_to", num_value <= attr_num);
152 TEST_BOL_ATTR("boolean_equals", bool_value == attr_bool);
153 TEST_BOL_ATTR("boolean_not_equals", bool_value != attr_bool);
154 TEST_STR_ATTR("contains", str_value.find(attr_str) != std::string::npos);
155
156#undef TEST_STR_ATTR
157#undef TEST_NUM_ATTR
158#undef TEST_BOL_ATTR
159
160 return true;
161 }
162}
163
164namespace { // Support functions
165 bool internal_conditional_passed(const vconfig& cond)
166 {
167 if(cond.has_child("true")) {
168 return true;
169 }
170 if(cond.has_child("false")) {
171 return false;
172 }
173
174 static const std::set<std::string> skip
175 {"then", "else", "elseif", "not", "and", "or", "do"};
176
177 for(const auto& [key, filter] : cond.all_ordered()) {
178 if(!utils::contains(skip, key)) {
179 assert(resources::lua_kernel);
180 if(!resources::lua_kernel->run_wml_conditional(key, filter)) {
181 return false;
182 }
183 }
184 }
185
186 return true;
187 }
188
189} // end anonymous namespace (support functions)
190
191
193{
194 bool matches = internal_conditional_passed(cond);
195
196 // Handle [and], [or], and [not] with in-order precedence
197 for(const auto& [key, filter] : cond.all_ordered()) {
198 // Handle [and]
199 if(key == "and") {
200 matches = matches && conditional_passed(filter);
201 }
202 // Handle [or]
203 else if(key == "or") {
204 matches = matches || conditional_passed(filter);
205 }
206 // Handle [not]
207 else if(key == "not") {
208 matches = matches && !conditional_passed(filter);
209 }
210 }
211
212 return matches;
213}
214
215} // end namespace game_events
double t
Variant for storing WML attributes.
bool has_attribute(std::string_view key) const
Definition config.cpp:157
virtual const std::vector< team > & teams() const override
virtual const unit_map & units() const override
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:71
std::size_t size() const
Get the number of units on the list.
This class stores all the data for a single 'side' (in game nomenclature).
Definition team.hpp:74
recall_list_manager & recall_list()
Definition team.hpp:242
std::string save_id_or_number() const
Definition team.hpp:259
This class represents a single unit of a specific type.
Definition unit.hpp:39
A variable-expanding proxy for the config class.
Definition variable.hpp:45
boost::iterator_range< all_children_iterator > all_ordered() const
Definition variable.hpp:190
bool has_child(const std::string &key) const
Returns whether or not *this has a child whose key is key.
Definition variable.cpp:316
static lg::log_domain log_engine("engine")
#define TEST_BOL_ATTR(name, test)
#define TEST_NUM_ATTR(name, test)
#define TEST_STR_ATTR(name, test)
static lg::log_domain log_wml("wml")
Define conditionals for the game's events mechanism, a.k.a.
Definitions for the interface to Wesnoth Markup Language (WML).
#define ERR_WML
const config * cfg
Standard logging facilities (interface).
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp > > &ranges)
Definition math.hpp:85
std::vector< std::pair< int, int > > default_counts
bool variable_matches(const vconfig &values)
bool have_location(const vconfig &cfg)
bool have_unit(const vconfig &cfg)
Domain specific events.
bool conditional_passed(const vconfig &cond)
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
Definition log.cpp:550
game_board * gameboard
Definition resources.cpp:20
game_data * gamedata
Definition resources.cpp:22
game_lua_kernel * lua_kernel
Definition resources.cpp:25
filter_context * filter_con
Definition resources.cpp:23
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition general.hpp:88
std::vector< std::pair< int, int > > parse_ranges_unsigned(const std::string &str)
Handles a comma-separated list of inputs to parse_range, in a context that does not expect negative v...
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
static map_location::direction n
#define i