The Battle for Wesnoth  1.17.0-dev
movetype.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 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 #pragma once
16 
17 #include "config.hpp"
19 
20 class attack_type;
21 namespace 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  */
43 class movetype
44 {
45 public:
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  class terrain_defense;
90 
91 private:
92 
93  /**
94  * Stores a set of data based on terrain, in some cases with raw pointers to
95  * other instances of terrain_info (the fallback_).
96  *
97  * The data can either be a single instance (in which case it's
98  * writable and stored in unique_data_) or may have already been shared
99  * (via make_data_shareable()), in which case it's stored in shared_data_.
100  * There will always be exactly one of those two that's non-null,
101  * get_data() returns it from where-ever it is.
102  */
104  {
105  /** The terrain-based data. */
106  class data;
107  // The data class is not defined here to keep the header file cleaner.
108 
109  public:
110  /** The parameters used when calculating a terrain-based value. */
111  struct parameters;
112 
113  explicit terrain_info(const parameters & params,
114  const terrain_info * fallback);
115  terrain_info(const config & cfg, const parameters & params,
116  const terrain_info * fallback);
117  ~terrain_info() override;
118 
119  // Instead of the standard copy and move constructors, there are ones
120  // that copy the data but require the caller to specify the fallback.
121  terrain_info(const terrain_info & that) = delete;
122  terrain_info(terrain_info && that) = delete;
123  explicit terrain_info(terrain_info && that,
124  const terrain_info * fallback);
125  terrain_info(const terrain_info & that,
126  const terrain_info * fallback);
127 
128  // Similarly to the copy and move constructors, the default assignments
129  // are deleted, because the caller needs to know about the siblings.
130  terrain_info & operator=(const terrain_info & that) = delete;
131  terrain_info & operator=(terrain_info && that) = delete;
132  void copy_data(const movetype::terrain_info & that);
133  void swap_data(movetype::terrain_info & that);
134 
135  /** Returns whether or not our data is empty. */
136  bool empty() const;
137  /** Merges the given config over the existing values. */
138  void merge(const config & new_values, bool overwrite,
139  const std::vector<movetype::terrain_info *> & dependants);
140 
141  // Implementation of terrain_costs
142  int value(const t_translation::terrain_code & terrain) const override;
143  void write(config & cfg, const std::string & child_name="", bool merged=true) const override;
144  std::unique_ptr<terrain_costs> make_standalone() const override;
145 
146  private:
147  /**
148  * Move data to an immutable copy in shared_data_, no-op if the data
149  * is already in shared_data_.
150  */
151  void make_data_shareable() const;
152  /**
153  * Copy the immutable data back to unique_data_, no-op if the data
154  * is already in unique_data_.
155  */
156  void make_data_writable() const;
157  /**
158  * Returns either *unique_data_ or *shared_data_, choosing the one that
159  * currently holds the data.
160  */
161  const data & get_data() const;
162 
163  private:
164  std::unique_ptr<data> unique_data_;
165  std::shared_ptr<const data> shared_data_;
166  const terrain_info * const fallback_;
167  };
168 
169 
170 public:
171  /**
172  * Magic value that signifies a hex is unreachable.
173  * The UNREACHABLE macro in the data tree should match this value.
174  */
175  static const int UNREACHABLE = 99;
176 
177  /** Stores a set of defense levels. */
179  {
182 
183  public:
184  terrain_defense() : min_(params_min_, nullptr), max_(params_max_, nullptr) {}
185  explicit terrain_defense(const config & cfg) :
186  min_(cfg, params_min_, nullptr), max_(cfg, params_max_, nullptr)
187  {}
188  terrain_defense(const terrain_defense & that);
190  terrain_defense & operator=(const terrain_defense & that);
191  terrain_defense & operator=(terrain_defense && that);
192 
193  /** Returns the defense associated with the given terrain. */
194  int defense(const t_translation::terrain_code & terrain) const
195  { return std::max(min_.value(terrain), max_.value(terrain)); }
196  /** Returns whether there is a defense cap associated to this terrain. */
197  bool capped(const t_translation::terrain_code & terrain) const
198  { return min_.value(terrain) != 0; }
199  /**
200  * Merges the given config over the existing costs.
201  * (Not overwriting implies adding.)
202  */
203  void merge(const config & new_data, bool overwrite);
204  /**
205  * Writes our data to a config, as a child if @a child_name is specified.
206  * (No child is created if there is no data.)
207  */
208  void write(config & cfg, const std::string & child_name="") const
209  { max_.write(cfg, child_name, false); }
210 
212 
213  private:
214  // There will be duplication of the config here, but it is a small
215  // config, and the duplication allows greater code sharing.
218  };
219 
220  /** Stores a set of resistances. */
222  {
223  public:
224  resistances() : cfg_() {}
225  explicit resistances(const config & cfg) : cfg_(cfg) {}
226 
227  /** Returns a map from attack types to resistances. */
228  utils::string_map damage_table() const;
229  /** Returns the resistance against the indicated attack. */
230  int resistance_against(const attack_type & attack) const;
231  /** Returns the resistance against the indicated damage type. */
232  int resistance_against(const std::string & damage_type) const;
233  /** Merges the given config over the existing costs. */
234  void merge(const config & new_data, bool overwrite);
235  /** Writes our data to a config, as a child if @a child_name is specified. */
236  void write(config & out_cfg, const std::string & child_name="") const;
237 
238  private:
240  };
241 
242 private:
244 
245 public:
246  movetype();
247  explicit movetype(const config & cfg);
248  movetype(const movetype & that);
249  movetype(movetype && that);
250  movetype &operator=(const movetype & that);
251  movetype &operator=(movetype && that);
252  // The default destructor is sufficient, despite the Rule of Five.
253  // The copy and assignment functions handle the pointers between
254  // terrain_cost_impl instances, but all of these instances are owned
255  // by this instance of movetype.
256  ~movetype() = default;
257 
258  friend void swap(movetype & a, movetype & b);
260 
261  // This class is basically just a holder for its various pieces, so
262  // provide access to those pieces on demand. There's no non-const
263  // getters for terrain_costs, as that's now an interface with only
264  // const functions in it, and because the logic for how the cascade and
265  // fallback mechanism works would be easier to handle in movetype itself.
266  terrain_defense & get_defense() { return defense_; }
267  resistances & get_resistances() { return resist_; }
268  // And const access:
269  const terrain_costs & get_movement() const { return movement_; }
270  const terrain_costs & get_vision() const { return vision_; }
271  const terrain_costs & get_jamming() const { return jamming_; }
272  const terrain_defense & get_defense() const { return defense_; }
273  const resistances & get_resistances() const { return resist_; }
274 
275  /** Returns whether or not *this is flagged as a flying movement type. */
276  bool is_flying() const { return flying_; }
277  /** Sets whether or not *this is flagged as a flying movement type. */
278  void set_flying(bool flies=true) { flying_ = flies; }
279 
280  /** Returns the cost to move through the indicated terrain. */
281  int movement_cost(const t_translation::terrain_code & terrain, bool slowed=false) const
282  { return movement_.cost(terrain, slowed); }
283  /** Returns the cost to see through the indicated terrain. */
284  int vision_cost(const t_translation::terrain_code & terrain, bool slowed=false) const
285  { return vision_.cost(terrain, slowed); }
286  /** Returns the cost to "jam" through the indicated terrain. */
287  int jamming_cost(const t_translation::terrain_code & terrain, bool slowed=false) const
288  { return jamming_.cost(terrain, slowed); }
289 
290  /** Returns the defensive value of the indicated terrain. */
292  { return defense_.defense(terrain); }
293 
294  /** Returns the resistance against the indicated attack. */
295  int resistance_against(const attack_type & attack) const
296  { return resist_.resistance_against(attack); }
297  /** Returns the resistance against the indicated damage type. */
298  int resistance_against(const std::string & damage_type) const
299  { return resist_.resistance_against(damage_type); }
300  /** Returns a map from attack types to resistances. */
302  { return resist_.damage_table(); }
303 
304  /** Returns whether or not there are any terrain caps with respect to a set of terrains. */
305  bool has_terrain_defense_caps(const std::set<t_translation::terrain_code> & ts) const;
306  /** Returns whether or not there are any vision-specific costs. */
307  bool has_vision_data() const { return !vision_.empty(); }
308  /** Returns whether or not there are any jamming-specific costs. */
309  bool has_jamming_data() const { return !jamming_.empty(); }
310 
311  /**
312  * Merges the given config over the existing data, the config should have zero or more
313  * children named "movement_costs", "defense", etc. Only those children will be affected
314  * (in the case of movement and vision the cascaded values in vision and jamming will also
315  * be affected).
316  *
317  * If @a overwrite is true, the new values will replace the old ones. If it's false, the
318  * new values are relative improvements or maluses which will be applied on top of the old
319  * values.
320  *
321  * If the old values included defense caps and @a overwrite is false, the calculations are
322  * done with absolute values and then changed back to the old sign. This means that merge()
323  * doesn't create or remove defense caps when @a overwrite is false.
324  *
325  * If @a new_cfg["flying"] is provided, it overrides the old value, regardless of the value
326  * of @a overwrite.
327  *
328  * This neither adds nor removes special notes. One purpose of this function is to have
329  * [unit_type][movement_costs] partially overwrite data from [unit_type]movetype=, and it
330  * would be unhelpful if an unrelated [unit_type][special_note] cleared the movetype's
331  * special notes.
332  */
333  void merge(const config & new_cfg, bool overwrite=true);
334 
335  /**
336  * Merges the given config over the existing data.
337  * @a applies_to which type of movement to change ("movement_costs", etc)
338  * @a new_cfg data which could be one of the children of the config for the two-argument form of this function.
339  */
340  void merge(const config & new_cfg, const std::string & applies_to, bool overwrite=true);
341 
342  /** The set of applicable effects for movement types */
343  static const std::set<std::string> effects;
344 
345  /** Contents of any [special_note] tags */
346  const std::vector<t_string>& special_notes() const { return special_notes_; }
347 
348  /** Writes the movement type data to the provided config. */
349  void write(config & cfg) const;
350 
351 private:
357 
358  bool flying_;
359  std::vector<t_string> special_notes_;
360 };
int defense_modifier(const t_translation::terrain_code &terrain) const
Returns the defensive value of the indicated terrain.
Definition: movetype.hpp:291
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:208
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:284
A const-only interface for how many (movement, vision, or "jamming") points a unit needs for each hex...
Definition: movetype.hpp:52
bool has_jamming_data() const
Returns whether or not there are any jamming-specific costs.
Definition: movetype.hpp:309
resistances & get_resistances()
Definition: movetype.hpp:267
std::map< std::string, t_string > string_map
const terrain_info *const fallback_
Definition: movetype.hpp:166
terrain_defense(const config &cfg)
Definition: movetype.hpp:185
terrain_info jamming_
Definition: movetype.hpp:354
std::unique_ptr< data > unique_data_
Definition: movetype.hpp:164
const resistances & get_resistances() const
Definition: movetype.hpp:273
const terrain_costs & get_jamming() const
Definition: movetype.hpp:271
int cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost associated with the given terrain.
Definition: movetype.hpp:68
#define a
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
Definition: movetype.hpp:175
bool has_vision_data() const
Returns whether or not there are any vision-specific costs.
Definition: movetype.hpp:307
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49
int resistance_against(const attack_type &attack) const
Returns the resistance against the indicated attack.
Definition: movetype.hpp:295
const terrain_defense & get_defense() const
Definition: movetype.hpp:272
int resistance_against(const std::string &damage_type) const
Returns the resistance against the indicated damage type.
Definition: movetype.hpp:298
const std::vector< t_string > & special_notes() const
Contents of any [special_note] tags.
Definition: movetype.hpp:346
The basic "size" of the unit - flying, small land, large land, etc.
Definition: movetype.hpp:43
bool capped(const t_translation::terrain_code &terrain) const
Returns whether there is a defense cap associated to this terrain.
Definition: movetype.hpp:197
Definitions for the interface to Wesnoth Markup Language (WML).
resistances(const config &cfg)
Definition: movetype.hpp:225
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:287
#define b
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:763
const terrain_costs & get_movement() const
Definition: movetype.hpp:269
terrain_defense & get_defense()
Definition: movetype.hpp:266
const terrain_costs & get_vision() const
Definition: movetype.hpp:270
static const std::set< std::string > effects
The set of applicable effects for movement types.
Definition: movetype.hpp:343
Stores a set of resistances.
Definition: movetype.hpp:221
Stores a set of data based on terrain, in some cases with raw pointers to other instances of terrain_...
Definition: movetype.hpp:103
utils::string_map damage_table() const
Returns a map from attack types to resistances.
Definition: movetype.hpp:301
std::shared_ptr< const data > shared_data_
Definition: movetype.hpp:165
void swap(config &lhs, config &rhs)
Implement non-member swap function for std::swap (calls config::swap).
Definition: config.cpp:1431
terrain_info movement_
Definition: movetype.hpp:352
bool flying_
Definition: movetype.hpp:358
static const terrain_info::parameters params_max_
Definition: movetype.hpp:181
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:281
bool is_flying() const
Returns whether or not *this is flagged as a flying movement type.
Definition: movetype.hpp:276
resistances resist_
Definition: movetype.hpp:356
terrain_defense defense_
Definition: movetype.hpp:355
terrain_info vision_
Definition: movetype.hpp:353
static const terrain_info::parameters mvj_params_
Limits for movement, vision and jamming.
Definition: movetype.hpp:243
The parameters used when calculating a terrain-based value.
Definition: movetype.cpp:54
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
int defense(const t_translation::terrain_code &terrain) const
Returns the defense associated with the given terrain.
Definition: movetype.hpp:194
void set_flying(bool flies=true)
Sets whether or not *this is flagged as a flying movement type.
Definition: movetype.hpp:278
Stores a set of defense levels.
Definition: movetype.hpp:178
static const terrain_info::parameters params_min_
Definition: movetype.hpp:180
std::vector< t_string > special_notes_
Definition: movetype.hpp:359