The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
abilities.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2006 - 2025
3 by Dominic Bolin <dominic.bolin@exong.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#pragma once
17
18#include "map/location.hpp"
19#include "units/ptr.hpp"
20#include "units/race.hpp" // for unit_race::GENDER
21
22
23#include <vector>
24class config;
25
26namespace wfl {
27 class map_formula_callable;
28}
29
31
32
33using ability_vector = std::vector<ability_ptr>;
34
36{
37public:
38
39 enum class active_on_t { offense, defense, both };
42
43 enum class affects_t { SELF = 1, OTHER = 2, EITHER = 3 };
44
45 unit_ability_t(std::string tag, config cfg, bool inside_attack);
46
47 static ability_ptr create(std::string tag, config cfg, bool inside_attack) {
48 return std::make_shared<unit_ability_t>(tag, cfg, inside_attack);
49 }
50
51 static void do_compat_fixes(config& cfg, const std::string& tag, bool inside_attack);
52
53 const std::string& tag() const { return tag_; };
54 const std::string& id() const { return id_; };
55 bool in_specials_tag() const { return in_specials_tag_; };
56 const config& cfg() const { return cfg_; };
57
58 active_on_t active_on() const { return active_on_; };
59 apply_to_t apply_to() const { return apply_to_; };
60 double priority() const { return priority_; };
61
64
65 //has no effect in [specials]
67 //has no effect in [specials]
68 bool affects_self() const { return affects_self_; }
69 //has no effect in [specials]
70 bool affects_enemies() const { return affects_enemies_; }
71
73 {
76 // a unique id used for help topics, generated from name and id.
77 // doesn't include the "ability_" prefix. Derived from cfg["unique_id"].
78 std::string help_topic_id;
79 };
80
81 //Generates a unique id to be used to identify the help page for this ability.
82 static std::string get_help_topic_id(const config& cfg);
83 std::string get_help_topic_id() const;
84
85
86 std::string get_name(bool is_inactive = false, unit_race::GENDER = unit_race::MALE) const;
87 std::string get_description(bool is_inactive = false, unit_race::GENDER = unit_race::MALE) const;
88
89 //checks whether the ability is active according to the active_on= attribute.
90 bool active_on_matches(bool student_is_attacker) const;
91
92
93 //checks whether the ability matches the filter specified in a [filter_special] or [filter_ability]
94 bool matches_filter(const config& filter) const;
95 void write(config& abilities_cfg);
96
97
98 static void parse_vector(const config& abilities_cfg, ability_vector& res, bool inside_attack);
99 static config vector_to_cfg(const ability_vector& abilities);
100 static ability_vector cfg_to_vector(const config& abilities_cfg, bool inside_attack);
101
102
103 static ability_vector filter_tag(const ability_vector& vec, const std::string& tag);
104 static ability_vector clone(const ability_vector& vec);
105
106 /**
107 * Substitute gettext variables in name and description of abilities and specials
108 * @param str The string in which the substitution is to be done
109 *
110 * @return The string `str` with all gettext variables substitutes with corresponding special properties
111 */
112 std::string substitute_variables(const std::string& str) const;
113
114
115
117 {
118 public:
122 recursion_guard() = delete;
124
125 /**
126 * Returns true if a level of recursion was available at the time when guard_against_recursion()
127 * created this object.
128 */
129 operator bool() const;
131 };
132
133 /**
134 * Tests which might otherwise cause infinite recursion should call this, check that the
135 * returned object evaluates to true, and then keep the object returned as long as the
136 * recursion might occur, similar to a reentrant mutex that's limited to a small number of
137 * reentrances.
138 *
139 * This only expects to be called in a single thread
140 */
142// recursion_guard guard_against_recursion(const attack_type& a) const;
143
144private:
145 std::string tag_;
146 std::string id_;
147 // abilities/specials inside [specials] tag follow a differnt syntax than in [abilities] tags, in paricular [filter_self] inside [specials] is equivalent to [filter_student] in abilities.
154 double priority_;
158
159 mutable bool currently_checked_;
160};
161
162
163/** Data typedef for active_ability_list. */
165{
172
173 /**
174 * Used by the formula in the ability.
175 * The REAL location of the student (not the 'we are assuming the student is at this position' location)
176 * once active_ability_list can contain abilities from different 'students', as it contains abilities from
177 * a unit aswell from its opponents (abilities with apply_to= opponent)
178 */
180 /**
181 * The location of the teacher, that is the unit who owns the ability tags
182 * (different from student because of [affect_adjacent])
183 */
185
186 const config& ability_cfg() const { return p_ability_->cfg(); }
187 const unit_ability_t& ability() const { return *p_ability_; }
188private:
189 /** The contents of the ability tag, never nullptr. */
191};
192
194{
195public:
197
198 // Implemented in unit_abilities.cpp
199 std::pair<int, map_location> highest(const std::string& key, int def = 0) const
200 {
201 return get_extremum(key, def, std::less<int>());
202 }
203 std::pair<int, map_location> lowest(const std::string& key, int def = 0) const
204 {
205 return get_extremum(key, def, std::greater<int>());
206 }
207
208 template<typename TComp>
209 std::pair<int, map_location> get_extremum(const std::string& key, int def, const TComp& comp) const;
210
211 // The following make this class usable with standard library algorithms and such
212 typedef std::vector<active_ability>::iterator iterator;
213 typedef std::vector<active_ability>::const_iterator const_iterator;
214
215 iterator begin() { return cfgs_.begin(); }
216 const_iterator begin() const { return cfgs_.begin(); }
217 iterator end() { return cfgs_.end(); }
218 const_iterator end() const { return cfgs_.end(); }
219
220 // Vector access
221 bool empty() const { return cfgs_.empty(); }
222 active_ability& front() { return cfgs_.front(); }
223 const active_ability& front() const { return cfgs_.front(); }
224 active_ability& back() { return cfgs_.back(); }
225 const active_ability& back() const { return cfgs_.back(); }
226 std::size_t size() { return cfgs_.size(); }
227
228 iterator erase(const iterator& erase_it) { return cfgs_.erase(erase_it); }
229 iterator erase(const iterator& first, const iterator& last) { return cfgs_.erase(first, last); }
230
231 template<typename... T>
232 void emplace_back(T&&... args) { cfgs_.emplace_back(args...); }
233
234 const map_location& loc() const { return loc_; }
235
236 /** Appends the abilities from @a other to @a this, ignores other.loc() */
237 void append(const active_ability_list& other)
238 {
239 std::copy(other.begin(), other.end(), std::back_inserter(cfgs_));
240 }
241
242 /**
243 * Appends any abilities from @a other for which the given condition returns true to @a this, ignores other.loc().
244 *
245 * @param other where to copy the elements from
246 * @param predicate a single-argument function that takes a reference to an element and returns a bool
247 */
248 template<typename Predicate>
249 void append_if(const active_ability_list& other, const Predicate& predicate)
250 {
251 std::copy_if(other.begin(), other.end(), std::back_inserter(cfgs_), predicate);
252 }
253
254private:
255 // Data
256 std::vector<active_ability> cfgs_;
258};
259
261
262public:
268
271
274
276 {
277 return specials_context_t{
278 {
279 std::move(attacking ? self : other),
280 } , {
281 std::move(attacking ? other : self),
282 }
283 };
284 }
285
286 void set_for_listing(bool for_listing)
287 {
288 is_for_listing = for_listing;
289 }
290
295
297 {
299 }
301 {
303 }
304
306 {
307 return &self == &attacker ? defender : attacker;
308 }
309
313
314 active_ability_list get_active_specials(const attack_type& at, const std::string& tag) const;
315
316 active_ability_list get_abilities_weapons(const std::string& tag, const unit& un) const;
317
318 bool has_active_special(const attack_type& at, const std::string& tag) const;
319 bool has_active_special_id(const attack_type& at, const std::string& id) const;
320 bool has_active_special_matching_filter(const attack_type& at, const config& filter) const;
321
322 static bool has_active_ability_id(const unit& un, map_location loc, const std::string& id);
323 static bool has_active_ability_matching_filter(const unit& un, map_location loc, const config& filter);
324
326
328
329 std::vector<unit_ability_t::tooltip_info> special_tooltips(const attack_type& at, boost::dynamic_bitset<>& active_list) const;
330 std::vector<unit_ability_t::tooltip_info> abilities_special_tooltips(const attack_type& at, boost::dynamic_bitset<>& active_list) const;
331
332 std::string describe_weapon_specials(const attack_type& at) const;
333 std::string describe_weapon_specials_value(const attack_type& at, const std::set<std::string>& checking_tags) const;
334
336
337};
338
339namespace unit_abilities
340{
341bool filter_base_matches(const config& cfg, int def);
342
344
346
348{
349 void set(value_modifier t, int val, const config& abil,const map_location &l);
351 int value{0};
352 const config* ability{nullptr};
354};
355
357{
358 public:
359 effect(active_ability_list list, int def, const specials_context_t* ctx = nullptr, EFFECTS wham = EFFECT_DEFAULT);
360 // Provide read-only access to the effect list:
361 typedef std::vector<individual_effect>::const_iterator iterator;
362 typedef std::vector<individual_effect>::const_iterator const_iterator;
363
365 { return composite_value_; }
369 { return effect_list_.begin(); }
371 { return effect_list_.end(); }
372 private:
373 /** Part of the constructor, calculates for a group of abilities with equal priority. */
374 void effect_impl(const active_ability_list& list, int def, const specials_context_t* ctx, EFFECTS wham);
375 std::vector<individual_effect> effect_list_;
378};
379
380
381}
std::vector< ability_ptr > ability_vector
Definition abilities.hpp:33
map_location loc
Definition move.cpp:172
double t
std::vector< active_ability >::iterator iterator
std::pair< int, map_location > lowest(const std::string &key, int def=0) const
void append_if(const active_ability_list &other, const Predicate &predicate)
Appends any abilities from other for which the given condition returns true to this,...
const active_ability & front() const
iterator erase(const iterator &first, const iterator &last)
std::vector< active_ability >::const_iterator const_iterator
const map_location & loc() const
std::vector< active_ability > cfgs_
iterator erase(const iterator &erase_it)
const_iterator begin() const
std::pair< int, map_location > get_extremum(const std::string &key, int def, const TComp &comp) const
void emplace_back(T &&... args)
active_ability & front()
std::pair< int, map_location > highest(const std::string &key, int def=0) const
active_ability & back()
active_ability_list(const map_location &loc=map_location())
map_location loc_
void append(const active_ability_list &other)
Appends the abilities from other to this, ignores other.loc()
const active_ability & back() const
const_iterator end() const
bool empty() const
std::size_t size()
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
self_and_other_ref self_and_other(const attack_type &self_att) const
bool has_active_special(const attack_type &at, const std::string &tag) const
Returns whether or not *this has a special ability with a tag or id equal to special.
void set_for_listing(bool for_listing)
active_ability_list get_abilities_weapons(const std::string &tag, const unit &un) const
bool is_special_active(const specials_combatant &wep, const unit_ability_t &ab, unit_ability_t::affects_t whom) const
Returns whether or not the given special is active for the specified unit, based on the current conte...
specials_combatant defender
std::vector< unit_ability_t::tooltip_info > special_tooltips(const attack_type &at, boost::dynamic_bitset<> &active_list) const
Returns a vector of names and descriptions for the specials of *this.
static bool has_active_ability_matching_filter(const unit &un, map_location loc, const config &filter)
std::string describe_weapon_specials_value(const attack_type &at, const std::set< std::string > &checking_tags) const
const specials_combatant & other(const specials_combatant &self) const
specials_combatant attacker
std::string describe_weapon_specials(const attack_type &at) const
Returns a comma-separated string of active names for the specials of *this.
void add_formula_context(wfl::map_formula_callable &callable) const
bool has_active_special_id(const attack_type &at, const std::string &id) const
specials_context_t(specials_context_t &&)=delete
std::vector< unit_ability_t::tooltip_info > abilities_special_tooltips(const attack_type &at, boost::dynamic_bitset<> &active_list) const
self_and_other_ref self_and_other(const unit &self_un) const
bool has_active_special_matching_filter(const attack_type &at, const config &filter) const
static specials_context_t make(specials_combatant &&self, specials_combatant &&other, bool attacking)
active_ability_list get_active_specials(const attack_type &at, const std::string &tag) const
static bool has_active_ability_id(const unit &un, map_location loc, const std::string &id)
specials_context_t(const specials_context_t &)=delete
active_ability_list get_active_combat_teachers(const attack_type &at) const
int get_composite_value() const
std::vector< individual_effect > effect_list_
const_iterator end() const
double get_composite_double_value() const
std::vector< individual_effect >::const_iterator const_iterator
std::vector< individual_effect >::const_iterator iterator
void effect_impl(const active_ability_list &list, int def, const specials_context_t *ctx, EFFECTS wham)
Part of the constructor, calculates for a group of abilities with equal priority.
const_iterator begin() const
const unit_ability_t * parent
recursion_guard(recursion_guard &&)=delete
recursion_guard(const recursion_guard &)=delete
std::string substitute_variables(const std::string &str) const
Substitute gettext variables in name and description of abilities and specials.
const std::string & tag() const
Definition abilities.hpp:53
double suppress_special_priority_
double suppress_special_priority() const
Definition abilities.hpp:62
apply_to_t apply_to() const
Definition abilities.hpp:59
static config vector_to_cfg(const ability_vector &abilities)
static void do_compat_fixes(config &cfg, const std::string &tag, bool inside_attack)
static void parse_vector(const config &abilities_cfg, ability_vector &res, bool inside_attack)
bool affects_enemies() const
Definition abilities.hpp:70
std::string get_description(bool is_inactive=false, unit_race::GENDER=unit_race::MALE) const
std::string id_
bool matches_filter(const config &filter) const
active_on_t active_on() const
Definition abilities.hpp:58
bool in_specials_tag() const
Definition abilities.hpp:55
active_on_t active_on_
static ability_vector filter_tag(const ability_vector &vec, const std::string &tag)
double priority() const
Definition abilities.hpp:60
double suppress_ability_priority() const
Definition abilities.hpp:63
static ability_ptr create(std::string tag, config cfg, bool inside_attack)
Definition abilities.hpp:47
bool currently_checked_
affects_allies_t affects_allies_
std::string tag_
static ability_vector clone(const ability_vector &vec)
const config & cfg() const
Definition abilities.hpp:56
std::string get_name(bool is_inactive=false, unit_race::GENDER=unit_race::MALE) const
std::string get_help_topic_id() const
recursion_guard guard_against_recursion(const unit &u) const
Tests which might otherwise cause infinite recursion should call this, check that the returned object...
void write(config &abilities_cfg)
double suppress_ability_priority_
static ability_vector cfg_to_vector(const config &abilities_cfg, bool inside_attack)
affects_allies_t affects_allies() const
Definition abilities.hpp:66
const std::string & id() const
Definition abilities.hpp:54
apply_to_t apply_to_
bool active_on_matches(bool student_is_attacker) const
bool affects_self() const
Definition abilities.hpp:68
This class represents a single unit of a specific type.
Definition unit.hpp:39
const config * cfg
bool filter_base_matches(const config &cfg, int def)
@ EFFECT_WITHOUT_CLAMP_MIN_MAX
std::shared_ptr< const unit_ability_t > const_ability_ptr
Definition ptr.hpp:39
std::shared_ptr< const unit > unit_const_ptr
Definition ptr.hpp:27
std::shared_ptr< const attack_type > const_attack_ptr
Definition ptr.hpp:34
std::shared_ptr< unit_ability_t > ability_ptr
Definition ptr.hpp:38
Data typedef for active_ability_list.
active_ability(const ability_ptr &p_ability, map_location student_loc, map_location teacher_loc)
const config & ability_cfg() const
const unit_ability_t & ability() const
map_location teacher_loc
The location of the teacher, that is the unit who owns the ability tags (different from student becau...
const_ability_ptr p_ability_
The contents of the ability tag, never nullptr.
map_location student_loc
Used by the formula in the ability.
Encapsulates the map of the game.
Definition location.hpp:46
static const map_location & null_location()
Definition location.hpp:103
const specials_combatant & self
const specials_combatant & other
void set(value_modifier t, int val, const config &abil, const map_location &l)