The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
movetype.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 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#pragma once
17
18#include "config.hpp"
20
21namespace t_translation { struct terrain_code; }
22
23
24/**
25 * The basic "size" of the unit - flying, small land, large land, etc.
26 * This encompasses terrain costs, defenses, and resistances.
27 *
28 * This class is used for both [movetype] and [unit] configs, which use the
29 * same data in their configs for [movement_costs], [defense], etc. However,
30 * the data for whether the unit flies is historically held in [movetype]'s
31 * "flies" vs [unit]'s "flying".
32 *
33 * Existing behavior of 1.14:
34 * * movetype::movetype(const config & cfg) will read only the "flies" key
35 * * movetype::merge(const config & cfg, bool overwrite) will read both keys,
36 * with "flying" taking priority if both are supplied
37 * * movetype::write() will write only the "flying" key
38 *
39 * @todo make this more logical. Ideas:
40 * * for 1.15, support both "flying" and "flies" in [movetype]
41 * * for 1.17 or later, drop the "flies"
42 */
44{
45public:
46 /**
47 * A const-only interface for how many (movement, vision, or "jamming") points a
48 * unit needs for each hex. Functions to modify the costs are exposed by the
49 * movetype instance owning this terrain_costs, so that changes to movement will
50 * cascade to the vision, etc.
51 */
53 {
54 public:
55 virtual ~terrain_costs() = default;
56
57 /**
58 * Returns the value associated with the given terrain.
59 *
60 * Calculated values are cached for later queries.
61 */
62 virtual int value(const t_translation::terrain_code & terrain) const = 0;
63
64 /**
65 * Returns the cost associated with the given terrain.
66 * Costs are doubled when @a slowed is true.
67 */
68 int cost(const t_translation::terrain_code & terrain, bool slowed=false) const
69 {
70 int result = value(terrain);
71 return slowed && result != movetype::UNREACHABLE ? 2 * result : result;
72 }
73
74 /**
75 * Does a sufficiently deep copy so that the returned object's lifespan
76 * is independent of other objects' lifespan. Never returns nullptr.
77 */
78 virtual std::unique_ptr<terrain_costs> make_standalone() const = 0;
79
80 /** Writes our data to a config. */
81 virtual void write(config & cfg, const std::string & child_name="", bool merged=true) const = 0;
82 };
83
84 /** Reverse of terrain_costs::write. Never returns nullptr. */
85 static std::unique_ptr<terrain_costs> read_terrain_costs(const config & cfg);
86
87 // Forward declaration so that terrain_info can friend the
88 // swap(terrain_defense, terrain_defense) function
89
90private:
91
92 /**
93 * Stores a set of data based on terrain, in some cases with raw pointers to
94 * other instances of terrain_info (the fallback_).
95 *
96 * The data can either be a single instance (in which case it's
97 * writable and stored in unique_data_) or may have already been shared
98 * (via make_data_shareable()), in which case it's stored in shared_data_.
99 * There will always be exactly one of those two that's non-null,
100 * get_data() returns it from where-ever it is.
101 */
103 {
104 /** The terrain-based data. */
105 class data;
106 // The data class is not defined here to keep the header file cleaner.
107
108 public:
109 /** The parameters used when calculating a terrain-based value. */
110 struct parameters;
111
112 explicit terrain_info(const parameters & params,
113 const terrain_info * fallback);
114 terrain_info(const config & cfg, const parameters & params,
115 const terrain_info * fallback);
116 ~terrain_info() override;
117
118 // Instead of the standard copy and move constructors, there are ones
119 // that copy the data but require the caller to specify the fallback.
120 terrain_info(const terrain_info & that) = delete;
121 terrain_info(terrain_info && that) = delete;
122 explicit terrain_info(terrain_info && that,
123 const terrain_info * fallback);
124 terrain_info(const terrain_info & that,
125 const terrain_info * fallback);
126
127 // Similarly to the copy and move constructors, the default assignments
128 // are deleted, because the caller needs to know about the siblings.
129 terrain_info & operator=(const terrain_info & that) = delete;
131 void copy_data(const movetype::terrain_info & that);
133
134 /** Returns whether or not our data is empty. */
135 bool empty() const;
136 /** Merges the given config over the existing values. */
137 void merge(const config & new_values, bool overwrite,
138 const std::vector<movetype::terrain_info *> & dependants);
139
140 // Implementation of terrain_costs
141 int value(const t_translation::terrain_code & terrain) const override;
142 void write(config & cfg, const std::string & child_name="", bool merged=true) const override;
143 std::unique_ptr<terrain_costs> make_standalone() const override;
144
145 private:
146 /**
147 * Move data to an immutable copy in shared_data_, no-op if the data
148 * is already in shared_data_.
149 */
150 void make_data_shareable() const;
151 /**
152 * Copy the immutable data back to unique_data_, no-op if the data
153 * is already in unique_data_.
154 */
155 void make_data_writable() const;
156 /**
157 * Returns either *unique_data_ or *shared_data_, choosing the one that
158 * currently holds the data.
159 */
160 const data & get_data() const;
161
162 private:
163 std::unique_ptr<data> unique_data_;
164 std::shared_ptr<const data> shared_data_;
165 const terrain_info * const fallback_;
166 };
167
168
169public:
170 /**
171 * Magic value that signifies a hex is unreachable.
172 * The UNREACHABLE macro in the data tree should match this value.
173 */
174 static const int UNREACHABLE = 99;
175
176 /** Stores a set of defense levels. */
178 {
181
182 public:
183 terrain_defense() : min_(params_min_, nullptr), max_(params_max_, nullptr) {}
184 explicit terrain_defense(const config & cfg) :
185 min_(cfg, params_min_, nullptr), max_(cfg, params_max_, nullptr)
186 {}
187 terrain_defense(const terrain_defense & that);
191
192 /** Returns the defense associated with the given terrain. */
193 int defense(const t_translation::terrain_code & terrain) const
194 { return std::max(min_.value(terrain), max_.value(terrain)); }
195 /** Returns whether there is a defense cap associated to this terrain. */
196 bool capped(const t_translation::terrain_code & terrain) const
197 { return min_.value(terrain) != 0; }
198 /**
199 * Merges the given config over the existing costs.
200 * (Not overwriting implies adding.)
201 */
202 void merge(const config & new_data, bool overwrite);
203 /**
204 * Writes our data to a config, as a child if @a child_name is specified.
205 * (No child is created if there is no data.)
206 */
207 void write(config & cfg, const std::string & child_name="") const
208 { max_.write(cfg, child_name, false); }
209
211
212 private:
213 // There will be duplication of the config here, but it is a small
214 // config, and the duplication allows greater code sharing.
217 };
218
219 /** Stores a set of resistances. */
221 {
222 public:
224 explicit resistances(const config & cfg) : cfg_(cfg) {}
225
226 /** Returns a map from damage types to resistances. */
228 /** Returns the vulnerability to the indicated damage type (higher means more damage). */
229 int resistance_against(const std::string & damage_type) const;
230 /** Merges the given config over the existing costs. */
231 void merge(const config & new_data, bool overwrite);
232 /** Writes our data to a config, as a child if @a child_name is specified. */
233 void write(config & out_cfg, const std::string & child_name="") const;
234
235 private:
237 };
238
239private:
241
242public:
243 movetype();
244 explicit movetype(const config & cfg);
245 movetype(const movetype & that);
246 movetype(movetype && that);
247 movetype &operator=(const movetype & that);
248 movetype &operator=(movetype && that);
249 // The default destructor is sufficient, despite the Rule of Five.
250 // The copy and assignment functions handle the pointers between
251 // terrain_cost_impl instances, but all of these instances are owned
252 // by this instance of movetype.
253 ~movetype() = default;
254
255 friend void swap(movetype & a, movetype & b);
257
258 // This class is basically just a holder for its various pieces, so
259 // provide access to those pieces on demand. There's no non-const
260 // getters for terrain_costs, as that's now an interface with only
261 // const functions in it, and because the logic for how the cascade and
262 // fallback mechanism works would be easier to handle in movetype itself.
265 // And const access:
266 const terrain_costs & get_movement() const { return movement_; }
267 const terrain_costs & get_vision() const { return vision_; }
268 const terrain_costs & get_jamming() const { return jamming_; }
269 const terrain_defense & get_defense() const { return defense_; }
270 const resistances & get_resistances() const { return resist_; }
271
272 /** Returns whether or not *this is flagged as a flying movement type. */
273 bool is_flying() const { return flying_; }
274 /** Sets whether or not *this is flagged as a flying movement type. */
275 void set_flying(bool flies=true) { flying_ = flies; }
276
277 /** Returns the cost to move through the indicated terrain. */
278 int movement_cost(const t_translation::terrain_code & terrain, bool slowed=false) const
279 { return movement_.cost(terrain, slowed); }
280 /** Returns the cost to see through the indicated terrain. */
281 int vision_cost(const t_translation::terrain_code & terrain, bool slowed=false) const
282 { return vision_.cost(terrain, slowed); }
283 /** Returns the cost to "jam" through the indicated terrain. */
284 int jamming_cost(const t_translation::terrain_code & terrain, bool slowed=false) const
285 { return jamming_.cost(terrain, slowed); }
286
287 /** Returns the defensive value of the indicated terrain. */
289 { return defense_.defense(terrain); }
290
291 /** Returns the vulnerability to the indicated damage type (higher means takes more damage). */
292 int resistance_against(const std::string & damage_type) const
293 { return resist_.resistance_against(damage_type); }
294 /** Returns a map from damage types to resistances. */
297
298 /** Returns whether or not there are any terrain caps with respect to a set of terrains. */
299 bool has_terrain_defense_caps(const std::set<t_translation::terrain_code> & ts) const;
300 /** Returns whether or not there are any vision-specific costs. */
301 bool has_vision_data() const { return !vision_.empty(); }
302 /** Returns whether or not there are any jamming-specific costs. */
303 bool has_jamming_data() const { return !jamming_.empty(); }
304
305 /**
306 * Merges the given config over the existing data, the config should have zero or more
307 * children named "movement_costs", "defense", etc. Only those children will be affected
308 * (in the case of movement and vision the cascaded values in vision and jamming will also
309 * be affected).
310 *
311 * If @a overwrite is true, the new values will replace the old ones. If it's false, the
312 * new values are relative improvements or maluses which will be applied on top of the old
313 * values.
314 *
315 * If the old values included defense caps and @a overwrite is false, the calculations are
316 * done with absolute values and then changed back to the old sign. This means that merge()
317 * doesn't create or remove defense caps when @a overwrite is false.
318 *
319 * If @a new_cfg["flying"] is provided, it overrides the old value, regardless of the value
320 * of @a overwrite.
321 *
322 * This neither adds nor removes special notes. One purpose of this function is to have
323 * [unit_type][movement_costs] partially overwrite data from [unit_type]movetype=, and it
324 * would be unhelpful if an unrelated [unit_type][special_note] cleared the movetype's
325 * special notes.
326 */
327 void merge(const config & new_cfg, bool overwrite=true);
328
329 /**
330 * Merges the given config over the existing data; this 3-argument version affects only the
331 * subelement identified by the @a applies_to argument.
332 *
333 * @param applies_to which type of movement to change ("movement_costs", etc)
334 * @param new_cfg data which could be one of the children of the config for the two-argument form of this function.
335 * @param overwrite if false, the new values will be added to the old.
336 */
337 void merge(const config & new_cfg, const std::string & applies_to, bool overwrite=true);
338
339 /** The set of applicable effects for movement types */
340 static const std::set<std::string> effects;
341
342 /** Contents of any [special_note] tags */
343 const std::vector<t_string>& special_notes() const { return special_notes_; }
344
345 /**
346 * Writes the movement type data to the provided config.
347 *
348 * There is no default value for the include_notes argument. Given the implied contract that a
349 * class with a constructor(const config&) and a write(config&) supports round-tripping the
350 * data, the default would need to be true. However, this method has only two callers, and
351 * neither of them want to include the notes:
352 *
353 * Movetype patching is unaffected by the notes, as they will be ignored by movetype::merge().
354 *
355 * [store_unit] is broken by the notes, because they end up in unit::special_notes_ instead of
356 * movetype::special_notes_ after the subsequent [unstore_unit].
357 *
358 * @param cfg output
359 * @param include_notes if false, omits any special notes
360 */
361 void write(config& cfg, bool include_notes) const;
362
363private:
369
371 std::vector<t_string> special_notes_;
372};
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
Stores a set of resistances.
Definition movetype.hpp:221
int resistance_against(const std::string &damage_type) const
Returns the vulnerability to the indicated damage type (higher means more damage).
Definition movetype.cpp:736
resistances(const config &cfg)
Definition movetype.hpp:224
void merge(const config &new_data, bool overwrite)
Merges the given config over the existing costs.
Definition movetype.cpp:746
utils::string_map_res damage_table() const
Returns a map from damage types to resistances.
Definition movetype.cpp:722
void write(config &out_cfg, const std::string &child_name="") const
Writes our data to a config, as a child if child_name is specified.
Definition movetype.cpp:765
A const-only interface for how many (movement, vision, or "jamming") points a unit needs for each hex...
Definition movetype.hpp:53
virtual int value(const t_translation::terrain_code &terrain) const =0
Returns the value associated with the given terrain.
virtual void write(config &cfg, const std::string &child_name="", bool merged=true) const =0
Writes our data to a config.
virtual ~terrain_costs()=default
int cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost associated with the given terrain.
Definition movetype.hpp:68
virtual std::unique_ptr< terrain_costs > make_standalone() const =0
Does a sufficiently deep copy so that the returned object's lifespan is independent of other objects'...
Stores a set of defense levels.
Definition movetype.hpp:178
terrain_defense & operator=(const terrain_defense &that)
Definition movetype.cpp:693
terrain_defense(const config &cfg)
Definition movetype.hpp:184
int defense(const t_translation::terrain_code &terrain) const
Returns the defense associated with the given terrain.
Definition movetype.hpp:193
void write(config &cfg, const std::string &child_name="") const
Writes our data to a config, as a child if child_name is specified.
Definition movetype.hpp:207
bool capped(const t_translation::terrain_code &terrain) const
Returns whether there is a defense cap associated to this terrain.
Definition movetype.hpp:196
static const terrain_info::parameters params_max_
Definition movetype.hpp:180
friend void swap(movetype::terrain_defense &a, movetype::terrain_defense &b)
Swap function for the terrain_defense class.
Definition movetype.cpp:494
static const terrain_info::parameters params_min_
Definition movetype.hpp:179
void merge(const config &new_data, bool overwrite)
Merges the given config over the existing costs.
Definition movetype.cpp:710
Stores a set of data based on terrain, in some cases with raw pointers to other instances of terrain_...
Definition movetype.hpp:103
void make_data_writable() const
Copy the immutable data back to unique_data_, no-op if the data is already in unique_data_.
Definition movetype.cpp:645
const data & get_data() const
Returns either *unique_data_ or *shared_data_, choosing the one that currently holds the data.
Definition movetype.cpp:624
std::unique_ptr< terrain_costs > make_standalone() const override
Does a sufficiently deep copy so that the returned object's lifespan is independent of other objects'...
Definition movetype.cpp:604
std::shared_ptr< const data > shared_data_
Definition movetype.hpp:164
void swap_data(movetype::terrain_info &that)
Swap function for the terrain_info class.
Definition movetype.cpp:481
void copy_data(const movetype::terrain_info &that)
This is only expected to be called either when 1) both this and that have no siblings,...
Definition movetype.cpp:467
bool empty() const
Returns whether or not our data is empty.
Definition movetype.cpp:534
void write(config &cfg, const std::string &child_name="", bool merged=true) const override
Writes our data to a config.
Definition movetype.cpp:585
int value(const t_translation::terrain_code &terrain) const override
Returns the value associated with the given terrain.
Definition movetype.cpp:573
terrain_info & operator=(const terrain_info &that)=delete
terrain_info(const terrain_info &that)=delete
terrain_info & operator=(terrain_info &&that)=delete
terrain_info(terrain_info &&that)=delete
~terrain_info() override
Destructor.
void make_data_shareable() const
Move data to an immutable copy in shared_data_, no-op if the data is already in shared_data_.
Definition movetype.cpp:666
const terrain_info *const fallback_
Definition movetype.hpp:165
void merge(const config &new_values, bool overwrite, const std::vector< movetype::terrain_info * > &dependants)
Merges the given config over the existing values.
Definition movetype.cpp:547
std::unique_ptr< data > unique_data_
Definition movetype.hpp:163
The basic "size" of the unit - flying, small land, large land, etc.
Definition movetype.hpp:44
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
Definition movetype.hpp:174
void write(config &cfg, bool include_notes) const
Writes the movement type data to the provided config.
Definition movetype.cpp:898
movetype()
Default constructor.
Definition movetype.cpp:783
static const std::set< std::string > effects
The set of applicable effects for movement types.
Definition movetype.hpp:895
const terrain_defense & get_defense() const
Definition movetype.hpp:269
void merge(const config &new_cfg, bool overwrite=true)
Merges the given config over the existing data, the config should have zero or more children named "m...
Definition movetype.cpp:854
const terrain_costs & get_vision() const
Definition movetype.hpp:267
bool has_vision_data() const
Returns whether or not there are any vision-specific costs.
Definition movetype.hpp:301
bool has_jamming_data() const
Returns whether or not there are any jamming-specific costs.
Definition movetype.hpp:303
bool has_terrain_defense_caps(const std::set< t_translation::terrain_code > &ts) const
Returns whether or not there are any terrain caps with respect to a set of terrains.
Definition movetype.cpp:846
int defense_modifier(const t_translation::terrain_code &terrain) const
Returns the defensive value of the indicated terrain.
Definition movetype.hpp:288
resistances resist_
Definition movetype.hpp:368
terrain_info movement_
Definition movetype.hpp:364
movetype & operator=(const movetype &that)
Definition movetype.cpp:518
const terrain_costs & get_jamming() const
Definition movetype.hpp:268
bool flying_
Definition movetype.hpp:370
terrain_defense defense_
Definition movetype.hpp:367
friend void swap(movetype::terrain_info &a, movetype::terrain_info &b)
~movetype()=default
static const terrain_info::parameters mvj_params_
Limits for movement, vision and jamming.
Definition movetype.hpp:78
static std::unique_ptr< terrain_costs > read_terrain_costs(const config &cfg)
Reverse of terrain_costs::write.
Definition movetype.cpp:422
int jamming_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to "jam" through the indicated terrain.
Definition movetype.hpp:284
const terrain_costs & get_movement() const
Definition movetype.hpp:266
const std::vector< t_string > & special_notes() const
Contents of any [special_note] tags.
Definition movetype.hpp:343
int vision_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to see through the indicated terrain.
Definition movetype.hpp:281
int resistance_against(const std::string &damage_type) const
Returns the vulnerability to the indicated damage type (higher means takes more damage).
Definition movetype.hpp:292
friend void swap(movetype &a, movetype &b)
Swap function for the movetype class, including its terrain_info members.
Definition movetype.cpp:507
std::vector< t_string > special_notes_
Definition movetype.hpp:371
resistances & get_resistances()
Definition movetype.hpp:264
int movement_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to move through the indicated terrain.
Definition movetype.hpp:278
void set_flying(bool flies=true)
Sets whether or not *this is flagged as a flying movement type.
Definition movetype.hpp:275
utils::string_map_res damage_table() const
Returns a map from damage types to resistances.
Definition movetype.hpp:295
const resistances & get_resistances() const
Definition movetype.hpp:270
terrain_defense & get_defense()
Definition movetype.hpp:263
terrain_info jamming_
Definition movetype.hpp:366
terrain_info vision_
Definition movetype.hpp:365
bool is_flying() const
Returns whether or not *this is flagged as a flying movement type.
Definition movetype.hpp:273
Definitions for the interface to Wesnoth Markup Language (WML).
const config * cfg
std::map< std::string, t_string, res_compare > string_map_res
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
The parameters used when calculating a terrain-based value.
Definition movetype.cpp:53
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
#define b