The Battle for Wesnoth  1.15.2+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 /// The basic "size" of the unit - flying, small land, large land, etc.
25 /// This encompasses terrain costs, defenses, and resistances.
26 ///
27 /// This class is used for both [movetype] and [unit] configs, which use the
28 /// same data in their configs for [movement_costs], [defense], etc. However,
29 /// the data for whether the unit flies is historically held in [movetype]'s
30 /// "flies" vs [unit]'s "flying".
31 ///
32 /// Existing behavior of 1.14:
33 /// * movetype::movetype(const config & cfg) will read only the "flies" key
34 /// * movetype::merge(const config & cfg, bool overwrite) will read both keys,
35 /// with "flying" taking priority if both are supplied
36 /// * movetype::write() will write only the "flying" key
37 ///
38 /// \todo make this more logical. Ideas:
39 /// * for 1.15, support both "flying" and "flies" in [movetype]
40 /// * for 1.17 or later, drop the "flies"
41 class movetype
42 {
43 public:
44  /// A const-only interface for how many (movement, vision, or "jamming") points a
45  /// unit needs for each hex. Functions to modify the costs are exposed by the
46  /// movetype instance owning this terrain_costs, so that changes to movement will
47  /// cascade to the vision, etc.
49  {
50  public:
51  virtual ~terrain_costs() = default;
52 
53  /// Returns the value associated with the given terrain.
54  ///
55  /// Calculated values are cached for later queries.
56  virtual int value(const t_translation::terrain_code & terrain) const = 0;
57 
58  /// Returns the cost associated with the given terrain.
59  /// Costs are doubled when @a slowed is true.
60  int cost(const t_translation::terrain_code & terrain, bool slowed=false) const
61  {
62  int result = value(terrain);
63  return slowed && result != movetype::UNREACHABLE ? 2 * result : result;
64  }
65 
66  /// Does a sufficiently deep copy so that the returned object's lifespan
67  /// is independent of other objects' lifespan. Never returns nullptr.
68  virtual std::unique_ptr<terrain_costs> make_standalone() const = 0;
69 
70  /// Writes our data to a config.
71  virtual void write(config & cfg, const std::string & child_name="", bool merged=true) const = 0;
72  };
73 
74  /// Reverse of terrain_costs::write. Never returns nullptr.
75  static std::unique_ptr<terrain_costs> read_terrain_costs(const config & cfg);
76 
77  // Forward declaration so that terrain_info can friend the
78  // swap(terrain_defense, terrain_defense) function
79  class terrain_defense;
80 
81 private:
82 
83  /// Stores a set of data based on terrain, in some cases with raw pointers to
84  /// other instances of terrain_info (the fallback_).
85  ///
86  /// The data can either be a single instance (in which case it's
87  /// writable and stored in unique_data_) or may have already been shared
88  /// (via make_data_shareable()), in which case it's stored in shared_data_.
89  /// There will always be exactly one of those two that's non-null,
90  /// get_data() returns it from where-ever it is.
91  class terrain_info : public terrain_costs
92  {
93  /// The terrain-based data.
94  class data;
95  // The data class is not defined here to keep the header file cleaner.
96 
97  public:
98  /// The parameters used when calculating a terrain-based value.
99  struct parameters;
100 
101  explicit terrain_info(const parameters & params,
102  const terrain_info * fallback);
103  terrain_info(const config & cfg, const parameters & params,
104  const terrain_info * fallback);
105  ~terrain_info() override;
106 
107  // Instead of the standard copy and move constructors, there are ones
108  // that copy the data but require the caller to specify the fallback.
109  terrain_info(const terrain_info & that) = delete;
110  terrain_info(terrain_info && that) = delete;
111  explicit terrain_info(terrain_info && that,
112  const terrain_info * fallback);
113  terrain_info(const terrain_info & that,
114  const terrain_info * fallback);
115 
116  // Similarly to the copy and move constructors, the default assignments
117  // are deleted, because the caller needs to know about the siblings.
118  terrain_info & operator=(const terrain_info & that) = delete;
119  terrain_info & operator=(terrain_info && that) = delete;
120  void copy_data(const movetype::terrain_info & that);
121  void swap_data(movetype::terrain_info & that);
122 
123  /// Returns whether or not our data is empty.
124  bool empty() const;
125  /// Merges the given config over the existing values.
126  void merge(const config & new_values, bool overwrite,
127  const std::vector<movetype::terrain_info *> & dependants);
128 
129  // Implementation of terrain_costs
130  int value(const t_translation::terrain_code & terrain) const override;
131  void write(config & cfg, const std::string & child_name="", bool merged=true) const override;
132  std::unique_ptr<terrain_costs> make_standalone() const override;
133 
134  private:
135  /// Move data to an immutable copy in shared_data_, no-op if the data
136  /// is already in shared_data_.
137  void make_data_shareable() const;
138  /// Copy the immutable data back to unique_data_, no-op if the data
139  /// is already in unique_data_.
140  void make_data_writable() const;
141  /// Returns either *unique_data_ or *shared_data_, choosing the one that
142  /// currently holds the data.
143  const data & get_data() const;
144 
145  private:
146  std::unique_ptr<data> unique_data_;
147  std::shared_ptr<const data> shared_data_;
148  const terrain_info * const fallback_;
149  };
150 
151 
152 public:
153  /// Magic value that signifies a hex is unreachable.
154  /// The UNREACHABLE macro in the data tree should match this value.
155  static const int UNREACHABLE = 99;
156 
157  /// Stores a set of defense levels.
159  {
162 
163  public:
164  terrain_defense() : min_(params_min_, nullptr), max_(params_max_, nullptr) {}
165  explicit terrain_defense(const config & cfg) :
166  min_(cfg, params_min_, nullptr), max_(cfg, params_max_, nullptr)
167  {}
168  terrain_defense(const terrain_defense & that);
170  terrain_defense & operator=(const terrain_defense & that);
171  terrain_defense & operator=(terrain_defense && that);
172 
173  /// Returns the defense associated with the given terrain.
175  { return std::max(min_.value(terrain), max_.value(terrain)); }
176  /// Returns whether there is a defense cap associated to this terrain.
178  { return min_.value(terrain) != 0; }
179  /// Merges the given config over the existing costs.
180  /// (Not overwriting implies adding.)
181  void merge(const config & new_data, bool overwrite);
182  /// Writes our data to a config, as a child if @a child_name is specified.
183  /// (No child is created if there is no data.)
184  void write(config & cfg, const std::string & child_name="") const
185  { max_.write(cfg, child_name, false); }
186 
188 
189  private:
190  // There will be duplication of the config here, but it is a small
191  // config, and the duplication allows greater code sharing.
194  };
195 
196  /// Stores a set of resistances.
198  {
199  public:
200  resistances() : cfg_() {}
201  explicit resistances(const config & cfg) : cfg_(cfg) {}
202 
203  /// Returns a map from attack types to resistances.
204  utils::string_map damage_table() const;
205  /// Returns the resistance against the indicated attack.
206  int resistance_against(const attack_type & attack) const;
207  /// Returns the resistance against the indicated damage type.
208  int resistance_against(const std::string & damage_type) const;
209  /// Merges the given config over the existing costs.
210  void merge(const config & new_data, bool overwrite);
211  /// Writes our data to a config, as a child if @a child_name is specified.
212  void write(config & out_cfg, const std::string & child_name="") const;
213 
214  private:
216  };
217 
218 private:
220 
221 public:
222  movetype();
223  explicit movetype(const config & cfg);
224  movetype(const movetype & that);
225  movetype(movetype && that);
226  movetype &operator=(const movetype & that);
227  movetype &operator=(movetype && that);
228  // The default destructor is sufficient, despite the Rule of Five.
229  // The copy and assignment functions handle the pointers between
230  // terrain_cost_impl instances, but all of these instances are owned
231  // by this instance of movetype.
232  ~movetype() = default;
233 
234  friend void swap(movetype & a, movetype & b);
236 
237  // This class is basically just a holder for its various pieces, so
238  // provide access to those pieces on demand. There's no non-const
239  // getters for terrain_costs, as that's now an interface with only
240  // const functions in it, and because the logic for how the cascade and
241  // fallback mechanism works would be easier to handle in movetype itself.
242  terrain_defense & get_defense() { return defense_; }
243  resistances & get_resistances() { return resist_; }
244  // And const access:
245  const terrain_costs & get_movement() const { return movement_; }
246  const terrain_costs & get_vision() const { return vision_; }
247  const terrain_costs & get_jamming() const { return jamming_; }
248  const terrain_defense & get_defense() const { return defense_; }
249  const resistances & get_resistances() const { return resist_; }
250 
251  /// Returns whether or not *this is flagged as a flying movement type.
252  bool is_flying() const { return flying_; }
253  /// Sets whether or not *this is flagged as a flying movement type.
254  void set_flying(bool flies=true) { flying_ = flies; }
255 
256  /// Returns the cost to move through the indicated terrain.
258  { return movement_.cost(terrain, slowed); }
259  /// Returns the cost to see through the indicated terrain.
260  int vision_cost(const t_translation::terrain_code & terrain, bool slowed=false) const
261  { return vision_.cost(terrain, slowed); }
262  /// Returns the cost to "jam" through the indicated terrain.
264  { return jamming_.cost(terrain, slowed); }
265 
266  /// Returns the defensive value of the indicated terrain.
268  { return defense_.defense(terrain); }
269 
270  /// Returns the resistance against the indicated attack.
271  int resistance_against(const attack_type & attack) const
272  { return resist_.resistance_against(attack); }
273  /// Returns the resistance against the indicated damage type.
274  int resistance_against(const std::string & damage_type) const
275  { return resist_.resistance_against(damage_type); }
276  /// Returns a map from attack types to resistances.
278  { return resist_.damage_table(); }
279 
280  /// Returns whether or not there are any terrain caps with respect to a set of terrains.
281  bool has_terrain_defense_caps(const std::set<t_translation::terrain_code> & ts) const;
282  /// Returns whether or not there are any vision-specific costs.
283  bool has_vision_data() const { return !vision_.empty(); }
284  /// Returns whether or not there are any jamming-specific costs.
285  bool has_jamming_data() const { return !jamming_.empty(); }
286 
287  /// Merges the given config over the existing data, the config should have zero or more
288  /// children named "movement_costs", "defense", etc.
289  void merge(const config & new_cfg, bool overwrite=true);
290 
291  /// Merges the given config over the existing data.
292  /// @a applies_to which type of movement to change ("movement_costs", etc)
293  /// @a new_cfg data which could be one of the children of the config for the two-argument form of this function.
294  void merge(const config & new_cfg, const std::string & applies_to, bool overwrite=true);
295 
296  /// The set of applicable effects for movement types
297  static const std::set<std::string> effects;
298 
299  /// Writes the movement type data to the provided config.
300  void write(config & cfg) const;
301 
302 private:
308 
309  bool flying_;
310 };
int defense_modifier(const t_translation::terrain_code &terrain) const
Returns the defensive value of the indicated terrain.
Definition: movetype.hpp:267
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:184
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:260
A const-only interface for how many (movement, vision, or "jamming") points a unit needs for each hex...
Definition: movetype.hpp:48
bool has_jamming_data() const
Returns whether or not there are any jamming-specific costs.
Definition: movetype.hpp:285
resistances & get_resistances()
Definition: movetype.hpp:243
std::map< std::string, t_string > string_map
const terrain_info *const fallback_
Definition: movetype.hpp:148
terrain_defense(const config &cfg)
Definition: movetype.hpp:165
terrain_info jamming_
Definition: movetype.hpp:305
std::unique_ptr< data > unique_data_
Definition: movetype.hpp:146
const resistances & get_resistances() const
Definition: movetype.hpp:249
const terrain_costs & get_jamming() const
Definition: movetype.hpp:247
int cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost associated with the given terrain.
Definition: movetype.hpp:60
#define a
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
Definition: movetype.hpp:155
bool has_vision_data() const
Returns whether or not there are any vision-specific costs.
Definition: movetype.hpp:283
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:50
int resistance_against(const attack_type &attack) const
Returns the resistance against the indicated attack.
Definition: movetype.hpp:271
const terrain_defense & get_defense() const
Definition: movetype.hpp:248
int resistance_against(const std::string &damage_type) const
Returns the resistance against the indicated damage type.
Definition: movetype.hpp:274
The basic "size" of the unit - flying, small land, large land, etc.
Definition: movetype.hpp:41
bool capped(const t_translation::terrain_code &terrain) const
Returns whether there is a defense cap associated to this terrain.
Definition: movetype.hpp:177
Definitions for the interface to Wesnoth Markup Language (WML).
resistances(const config &cfg)
Definition: movetype.hpp:201
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:263
#define b
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:762
const terrain_costs & get_movement() const
Definition: movetype.hpp:245
terrain_defense & get_defense()
Definition: movetype.hpp:242
const terrain_costs & get_vision() const
Definition: movetype.hpp:246
static const std::set< std::string > effects
The set of applicable effects for movement types.
Definition: movetype.hpp:297
Stores a set of resistances.
Definition: movetype.hpp:197
Stores a set of data based on terrain, in some cases with raw pointers to other instances of terrain_...
Definition: movetype.hpp:91
utils::string_map damage_table() const
Returns a map from attack types to resistances.
Definition: movetype.hpp:277
std::shared_ptr< const data > shared_data_
Definition: movetype.hpp:147
void swap(config &lhs, config &rhs)
Implement non-member swap function for std::swap (calls config::swap).
Definition: config.cpp:1386
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:130
terrain_info movement_
Definition: movetype.hpp:303
bool flying_
Definition: movetype.hpp:309
static const terrain_info::parameters params_max_
Definition: movetype.hpp:161
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:257
bool is_flying() const
Returns whether or not *this is flagged as a flying movement type.
Definition: movetype.hpp:252
resistances resist_
Definition: movetype.hpp:307
terrain_defense defense_
Definition: movetype.hpp:306
terrain_info vision_
Definition: movetype.hpp:304
static const terrain_info::parameters mvj_params_
Limits for movement, vision and jamming.
Definition: movetype.hpp:219
The parameters used when calculating a terrain-based value.
Definition: movetype.cpp:55
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
int defense(const t_translation::terrain_code &terrain) const
Returns the defense associated with the given terrain.
Definition: movetype.hpp:174
void set_flying(bool flies=true)
Sets whether or not *this is flagged as a flying movement type.
Definition: movetype.hpp:254
Stores a set of defense levels.
Definition: movetype.hpp:158
static const terrain_info::parameters params_min_
Definition: movetype.hpp:160