The Battle for Wesnoth  1.15.1+dev
movetype.cpp
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 /**
16  * @file
17  * Handle movement types.
18  */
19 
20 #include "movetype.hpp"
21 
22 #include "game_board.hpp"
23 #include "game_config_manager.hpp"
24 #include "log.hpp"
25 #include "map/map.hpp"
26 #include "terrain/translation.hpp"
27 #include "terrain/type_data.hpp"
28 #include "units/types.hpp" // for attack_type
29 
30 static lg::log_domain log_config("config");
31 #define ERR_CF LOG_STREAM(err, log_config)
32 #define WRN_CF LOG_STREAM(warn, log_config)
33 
34 
35 /* *** parameters *** */
36 
37 
38 namespace { // Some functions for use with parameters::eval.
39 
40  /// Converts config defense values to a "max" value.
41  int config_to_max(int value)
42  {
43  return value < 0 ? -value : value;
44  }
45 
46  /// Converts config defense values to a "min" value.
47  int config_to_min(int value)
48  {
49  return value < 0 ? -value : 0;
50  }
51 }
52 
53 
54 /// The parameters used when calculating a terrain-based value.
56 {
57  int min_value; /// The smallest allowable value.
58  int max_value; /// The largest allowable value.
59  int default_value; /// The default value (if no data is available).
60 
61  int (*eval)(int); /// Converter for values taken from a config. May be nullptr.
62 
63  bool use_move; /// Whether to look at underlying movement or defense terrains.
64  bool high_is_good; /// Whether we are looking for highest or lowest (unless inverted by the underlying terrain).
65 
66  parameters(int min, int max, int (*eval_fun)(int)=nullptr, bool move=true, bool high=false) :
67  min_value(min), max_value(max), default_value(high ? min : max),
68  eval(eval_fun), use_move(move), high_is_good(high)
69  {}
70 };
71 
72 
73 /// Limits for movement, vision and jamming
76 
78  movetype::terrain_defense::params_min_(0, 100, config_to_min, false, true);
80  movetype::terrain_defense::params_max_(0, 100, config_to_max, false, false);
81 
82 
83 /* *** data *** */
84 
85 
87 {
88 public:
89  /// Constructor.
90  /// @a params must be long-lived (typically a static variable).
91  explicit data(const parameters & params) :
92  cfg_(), cache_(), params_(params)
93  {}
94  /// Constructor.
95  /// @a params must be long-lived (typically a static variable).
96  data(const config & cfg, const parameters & params) :
97  cfg_(cfg), cache_(), params_(params)
98  {}
99 
100  // The copy constructor does not bother copying the cache since
101  // typically the cache will be cleared shortly after the copy.
102  data(const data & that) :
103  cfg_(that.cfg_), cache_(), params_(that.params_)
104  {}
105 
106  /// Clears the cached data (presumably our fallback has changed).
107  void clear_cache() const;
108  /// Tests if merging @a new_values would result in changes.
109  bool config_has_changes(const config & new_values, bool overwrite) const;
110  /// Tests for no data in this object.
111  bool empty() const { return cfg_.empty(); }
112  /// Merges the given config over the existing costs.
113  void merge(const config & new_values, bool overwrite);
114  /// Read-only access to our parameters.
115  const parameters & params() const { return params_; }
116  /// Returns the value associated with the given terrain.
118  const terrain_info * fallback) const
119  { return value(terrain, fallback, 0); }
120  /// If there is data, writes it to the config.
121  void write(config & out_cfg, const std::string & child_name) const;
122  /// If there is (merged) data, writes it to the config.
123  void write(config & out_cfg, const std::string & child_name,
124  const terrain_info * fallback) const;
125 
126 private:
127  /// Calculates the value associated with the given terrain.
128  int calc_value(const t_translation::terrain_code & terrain,
129  const terrain_info * fallback, unsigned recurse_count) const;
130  /// Returns the value associated with the given terrain (possibly cached).
131  int value(const t_translation::terrain_code & terrain,
132  const terrain_info * fallback, unsigned recurse_count) const;
133 
134 private:
135  typedef std::map<t_translation::terrain_code, int> cache_t;
136 
137  /// Config describing the terrain values.
139  /// Cache of values based on the config.
140  mutable cache_t cache_;
141  /// Various parameters used when calculating values.
143 };
144 
145 
146 /**
147  * Clears the cached data (presumably our fallback has changed).
148  */
150 {
151  cache_.clear();
152 }
153 
154 
155 /**
156  * Tests if merging @a new_values would result in changes.
157  * This allows the shared data to actually work, as otherwise each unit created
158  * via WML (including unstored units) would "overwrite" its movement data with
159  * a usually identical copy and thus break the sharing.
160  */
162  bool overwrite) const
163 {
164  if ( overwrite ) {
165  for (const config::attribute & a : new_values.attribute_range())
166  if ( a.second != cfg_[a.first] )
167  return true;
168  }
169  else {
170  for (const config::attribute & a : new_values.attribute_range())
171  if ( a.second.to_int() != 0 )
172  return true;
173  }
174 
175  // If we make it here, new_values has no changes for us.
176  return false;
177 }
178 
179 
180 /**
181  * Merges the given config over the existing costs.
182  *
183  * After calling this function, the caller must call clear_cache on any
184  * terrain_info that uses this one as a fallback.
185  *
186  * @param[in] new_values The new values.
187  * @param[in] overwrite If true, the new values overwrite the old.
188  * If false, the new values are added to the old.
189  */
190 void movetype::terrain_info::data::merge(const config & new_values, bool overwrite)
191 {
192  if ( overwrite )
193  // We do not support child tags here, so do not copy any that might
194  // be in the input. (If in the future we need to support child tags,
195  // change "merge_attributes" to "merge_with".)
196  cfg_.merge_attributes(new_values);
197  else {
198  for (const config::attribute & a : new_values.attribute_range()) {
199  config::attribute_value & dest = cfg_[a.first];
200  int old = dest.to_int(params_.max_value);
201 
202  // The new value is the absolute value of the old plus the
203  // provided value, capped between minimum and maximum, then
204  // given the sign of the old value.
205  // (Think defenses for why we might have negative values.)
206  int value = std::abs(old) + a.second.to_int(0);
207  value = std::max(params_.min_value, std::min(value, params_.max_value));
208  if ( old < 0 )
209  value = -value;
210 
211  dest = value;
212  }
213  }
214 
215  // The new data has invalidated the cache.
216  clear_cache();
217 }
218 
219 
220 /**
221  * If there is data, writes it to a config.
222  * @param[out] out_cfg The config that will receive the data.
223  * @param[in] child_name If not empty, create and write to a child config with this tag.
224  * This child will *not* be created if there is no data to write.
225  */
227  config & out_cfg, const std::string & child_name) const
228 {
229  if ( cfg_.empty() )
230  return;
231 
232  if ( child_name.empty() )
233  out_cfg.merge_with(cfg_);
234  else
235  out_cfg.add_child(child_name, cfg_);
236 }
237 
238 
239 /**
240  * Writes merged data to a config.
241  * @param[out] out_cfg The config that will receive the data.
242  * @param[in] child_name If not empty, create and write to a child config with this tag.
243  * This *will* be created even if there is no data to write.
244  * @param[in] fallback If not nullptr, its data will be merged with ours for the write.
245  */
247  config & out_cfg, const std::string & child_name, const terrain_info * fallback) const
248 {
249  // Get a place to write to.
250  config & merged = child_name.empty() ? out_cfg : out_cfg.add_child(child_name);
251 
252  if ( fallback )
253  fallback->write(merged, "", true);
254  merged.merge_with(cfg_);
255 }
256 
257 
258 /**
259  * Calculates the value associated with the given terrain.
260  * This is separate from value() to separate the calculating of the
261  * value from the caching of it.
262  * @param[in] terrain The terrain whose value is requested.
263  * @param[in] fallback Consulted if we are missing data.
264  * @param[in] recurse_count Detects (probable) infinite recursion.
265  */
268  const terrain_info * fallback,
269  unsigned recurse_count) const
270 {
271  // Infinite recursion detection:
272  if ( recurse_count > 100 ) {
273  ERR_CF << "infinite terrain_info recursion on "
274  << (params_.use_move ? "movement" : "defense") << ": "
276  << " depth " << recurse_count << '\n';
277  return params_.default_value;
278  }
279 
280  ter_data_cache tdata;
282  tdata = game_config_manager::get()->terrain_types(); //This permits to get terrain info in unit help pages from the help in title screen, even if there is no residual gamemap object
283  }
284  assert(tdata);
285 
286  // Get a list of underlying terrains.
287  const t_translation::ter_list & underlying = params_.use_move ?
288  tdata->underlying_mvt_terrain(terrain) :
289  tdata->underlying_def_terrain(terrain);
290  assert(!underlying.empty());
291 
292 
293  if ( underlying.size() == 1 && underlying.front() == terrain )
294  {
295  // This is not an alias; get the value directly.
296  int result = params_.default_value;
297 
298  const std::string & id = tdata->get_terrain_info(terrain).id();
299  if (const config::attribute_value *val = cfg_.get(id)) {
300  // Read the value from our config.
301  result = val->to_int(params_.default_value);
302  if ( params_.eval != nullptr )
303  result = params_.eval(result);
304  }
305  else if ( fallback != nullptr ) {
306  // Get the value from our fallback.
307  result = fallback->value(terrain);
308  }
309 
310  // Validate the value.
311  if ( result < params_.min_value ) {
312  WRN_CF << "Terrain '" << terrain << "' has evaluated to " << result
313  << " (" << (params_.use_move ? "cost" : "defense")
314  << "), which is less than " << params_.min_value
315  << "; resetting to " << params_.min_value << ".\n";
316  result = params_.min_value;
317  }
318  if ( result > params_.max_value ) {
319  WRN_CF << "Terrain '" << terrain << "' has evaluated to " << result
320  << " (" << (params_.use_move ? "cost" : "defense")
321  << "), which is more than " << params_.max_value
322  << "; resetting to " << params_.max_value << ".\n";
323  result = params_.max_value;
324  }
325 
326  return result;
327  }
328  else
329  {
330  // This is an alias; select the best of all underlying terrains.
331  bool prefer_high = params_.high_is_good;
332  int result = params_.default_value;
333  if ( underlying.front() == t_translation::MINUS )
334  // Use the other value as the initial value.
335  result = result == params_.max_value ? params_.min_value :
336  params_.max_value;
337 
338  // Loop through all underlying terrains.
339  t_translation::ter_list::const_iterator i;
340  for ( i = underlying.begin(); i != underlying.end(); ++i )
341  {
342  if ( *i == t_translation::PLUS ) {
343  // Prefer what is good.
344  prefer_high = params_.high_is_good;
345  }
346  else if ( *i == t_translation::MINUS ) {
347  // Prefer what is bad.
348  prefer_high = !params_.high_is_good;
349  }
350  else {
351  // Test the underlying terrain's value against the best so far.
352  const int num = value(*i, fallback, recurse_count + 1);
353 
354  if ( ( prefer_high && num > result) ||
355  (!prefer_high && num < result) )
356  result = num;
357  }
358  }
359 
360  return result;
361  }
362 }
363 
364 
365 /**
366  * Returns the value associated with the given terrain (possibly cached).
367  * @param[in] terrain The terrain whose value is requested.
368  * @param[in] fallback Consulted if we are missing data.
369  * @param[in] recurse_count Detects (probable) infinite recursion.
370  */
373  const terrain_info * fallback,
374  unsigned recurse_count) const
375 {
376  // Check the cache.
377  std::pair<cache_t::iterator, bool> cache_it =
378  cache_.emplace(terrain, -127); // Bogus value that should never be seen.
379  if ( cache_it.second )
380  // The cache did not have an entry for this terrain, so calculate the value.
381  cache_it.first->second = calc_value(terrain, fallback, recurse_count);
382 
383  return cache_it.first->second;
384 }
385 
386 
387 /* *** terrain_info *** */
388 
389 
390 /**
391  * Constructor.
392  * @param[in] params The parameters to use when calculating values.
393  * This is stored as a reference, so it must be long-lived (typically a static variable).
394  * @param[in] fallback Used as a backup in case we are asked for data we do not have (think vision costs falling back to movement costs).
395  */
397  const terrain_info * fallback) :
398  unique_data_(new data(params)),
399  fallback_(fallback)
400 {
401 }
402 
403 
404 /**
405  * Constructor.
406  * @param[in] cfg An initial data set.
407  * @param[in] params The parameters to use when calculating values.
408  * This is stored as a reference, so it must be long-lived (typically a static variable).
409  * @param[in] fallback Used as a backup in case we are asked for data we do not have (think vision costs falling back to movement costs).
410  */
412  const terrain_info * fallback) :
413  unique_data_(new data(cfg, params)),
414  fallback_(fallback)
415 {
416 }
417 
418 /**
419  * Reverse of terrain_costs::write. Never returns nullptr.
420  * @param[in] cfg An initial data set
421  */
422 std::unique_ptr<movetype::terrain_costs> movetype::read_terrain_costs(const config & cfg)
423 {
424  return std::make_unique<terrain_info> (cfg, movetype::mvj_params_, nullptr);
425 }
426 
427 /**
428  * Copy constructor for callers that handle the fallback and cascade. This is
429  * intended for terrain_defense or movetype's copy constructors, where a
430  * similar set of terrain_infos will be created, complete with the same
431  * relationships between parts of the set.
432  *
433  * @param[in] that The terrain_info to copy.
434  * @param[in] fallback Used as a backup in case we are asked for data we do not have (think vision costs falling back to movement costs).
435  */
437  const terrain_info * fallback) :
438  fallback_(fallback)
439 {
440  assert(fallback ? !! that.fallback_ : ! that.fallback_);
441  copy_data(that);
442 }
443 
445  const terrain_info * fallback) :
446  fallback_(fallback)
447 {
448  assert(fallback ? !! that.fallback_ : ! that.fallback_);
449  swap_data(that);
450 }
451 
452 /**
453  * Destructor
454  *
455  * While this is simply the default destructor, it needs
456  * to be defined in this file so that it knows about ~data(), which
457  * is called from the smart pointers' destructor.
458  */
460 
461 /**
462  * This is only expected to be called either when
463  * 1) both this and @a that have no siblings, as happens when terrain_defense is copied, or
464  * 2) all of the siblings are being copied, as happens when movetype is copied.
465  */
467 {
468  that.make_data_shareable();
469  this->unique_data_.reset();
470  this->shared_data_ = that.shared_data_;
471 }
472 
473 /**
474  * Swap function for the terrain_info class
475  *
476  * This is only expected to be called either when
477  * 1) both this and @a that have no siblings, as happens when swapping two terrain_defenses, or
478  * 2) all of the siblings are being swapped, as happens when two movetypes are swapped.
479  */
481 {
482  // It doesn't matter whether they're both unique, both shared, or
483  // one unique with the other shared.
484  std::swap(this->unique_data_, that.unique_data_);
485  std::swap(this->shared_data_, that.shared_data_);
486 }
487 /**
488  * Swap function for the terrain_defense class
489  *
490  * This relies on all of the terrain_infos having no fallback and no cascade,
491  * an assumption which is provided by terrain_defense's constructors.
492  */
494 {
495  a.min_.swap_data(b.min_);
496  a.max_.swap_data(b.max_);
497 }
498 
499 /**
500  * Swap function for the movetype class, including its terrain_info members
501  *
502  * This relies on the two sets of the terrain_infos having their movement,
503  * vision and jamming cascaded in the same way. This assumption is provided by
504  * movetype's constructors.
505  */
507 {
511  swap(a.defense_, b.defense_);
512  std::swap(a.resist_, b.resist_);
513  std::swap(a.flying_, b.flying_);
514 }
515 
517 {
518  movetype m(that);
519  swap(*this, m);
520  return *this;
521 }
522 
524 {
525  swap(*this, that);
526  return *this;
527 }
528 
529 /**
530  * Returns whether or not our data is empty.
531  */
533 {
534  return get_data().empty();
535 }
536 
537 
538 /**
539  * Merges the given config over the existing values.
540  * @param[in] new_values The new values.
541  * @param[in] overwrite If true, the new values overwrite the old.
542  * If false, the new values are added to the old.
543  * @param[in] dependants Other instances that use this as a fallback.
544  */
545 void movetype::terrain_info::merge(const config & new_values, bool overwrite,
546  const std::vector<movetype::terrain_info * > & dependants)
547 {
548  if ( !get_data().config_has_changes(new_values, overwrite) )
549  // Nothing will change, so skip the copy-on-write.
550  return;
551 
552  // Copy-on-write.
553  //
554  // We also need to make our cascade writeable, because changes to this
555  // instance will change data that they receive when using this as their
556  // fallback. However, it's no problem for a writable instance to have a
557  // shareable instance as its fallback.
559  for (auto & dependant : dependants) {
560  // This will automatically clear the dependant's cache
561  dependant->make_data_writable();
562  }
563 
564  unique_data_->merge(new_values, overwrite);
565 }
566 
567 
568 /**
569  * Returns the value associated with the given terrain.
570  */
572 {
573  return get_data().value(terrain, fallback_);
574 }
575 
576 /**
577  * Writes our data to a config.
578  * @param[out] cfg The config that will receive the data.
579  * @param[in] child_name If not empty, create and write to a child config with this tag.
580  * @param[in] merged If true, our data will be merged with our fallback's, and it is possible an empty child will be created.
581  * If false, data will not be merged, and an empty child will not be created.
582  */
583 void movetype::terrain_info::write(config & cfg, const std::string & child_name,
584  bool merged) const
585 {
586  if ( !merged )
587  get_data().write(cfg, child_name);
588  else
589  get_data().write(cfg, child_name, fallback_);
590 }
591 
592 
593 /**
594  * Does a sufficiently deep copy so that the returned object's lifespan
595  * is independent of other objects' lifespan. Never returns nullptr.
596  *
597  * This implements terrain_costs's virtual method for getting an instance that
598  * doesn't depend on the lifespan of a terrain_defense or movetype object.
599  * This will do a deep copy of the data (with fallback_ already merged) if
600  * needed.
601  */
602 std::unique_ptr<movetype::terrain_costs> movetype::terrain_info::make_standalone() const
603 {
604  std::unique_ptr<terrain_costs> t;
605  if(!fallback_) {
606  // Call the copy constructor, which will make_data_shareable().
607  t = std::make_unique<terrain_info>(*this, nullptr);
608  }
609  else if(get_data().empty()) {
610  // Pure fallback.
611  t = fallback_->make_standalone();
612  }
613  else {
614  // Need to merge data.
615  config merged;
616  write(merged, "", true);
617  t = std::make_unique<terrain_info>(merged, get_data().params(), nullptr);
618  }
619  return t;
620 }
621 
623 {
624  assert(unique_data_ || shared_data_);
625  assert(! (unique_data_ && shared_data_));
626  if(unique_data_)
627  return *unique_data_;
628  return *shared_data_;
629 }
630 
631 /**
632  * Copy the immutable data back to unique_data_, no-op if the data
633  * is already in unique_data_.
634  *
635  * Ensures our data is not shared, and therefore that changes only
636  * affect this instance of terrain_info (and any instances using it
637  * as a fallback).
638  *
639  * This does not need to affect the fallback - it's no problem if a
640  * writable instance has a fallback to a shareable instance, although
641  * a shareable instance must not fallback to a writable instance.
642  */
644 {
645  if(!unique_data_)
646  {
647  // Const hack because this is not really changing the data.
648  auto t = const_cast<terrain_info *>(this);
649  t->unique_data_.reset(new data(*shared_data_));
650  t->shared_data_.reset();
651  }
652 
653  // As we're about to write data, invalidate the cache
654  unique_data_->clear_cache();
655 }
656 
657 /**
658  * Move data to an immutable copy in shared_data_, no-op if the data
659  * is already in shared_data_.
660  *
661  * This is recursive on the fallback chain, because if the data shouldn't be
662  * writable then the data shouldn't be writable via the fallback either.
663  */
665 {
666  if(!unique_data_)
667  return;
668 
669  if(fallback_)
671 
672  // Const hack because this is not really changing the data.
673  auto t = const_cast<terrain_info *>(this);
674  t->shared_data_ = std::move(t->unique_data_);
675 }
676 
677 /* *** terrain_defense *** */
678 
680  min_(that.min_, nullptr),
681  max_(that.max_, nullptr)
682 {
683 }
684 
686  min_(std::move(that.min_), nullptr),
687  max_(std::move(that.max_), nullptr)
688 {
689 }
690 
692 {
693  min_.copy_data(that.min_);
694  max_.copy_data(that.max_);
695  return *this;
696 }
697 
699 {
700  min_.swap_data(that.min_);
701  max_.swap_data(that.max_);
702  return *this;
703 }
704 /// Merges the given config over the existing costs.
705 /// (Not overwriting implies adding.)
706 void movetype::terrain_defense::merge(const config & new_data, bool overwrite)
707 {
708  min_.merge(new_data, overwrite, {});
709  max_.merge(new_data, overwrite, {});
710 }
711 
712 /* *** resistances *** */
713 
714 
715 /**
716  * Returns a map from attack types to resistances.
717  */
719 {
720  utils::string_map result;
721 
722  for (const config::attribute & attrb : cfg_.attribute_range()) {
723  result[attrb.first] = attrb.second;
724  }
725 
726  return result;
727 }
728 
729 
730 /**
731  * Returns the resistance against the indicated attack.
732  */
734 {
735  return cfg_[attack.type()].to_int(100);
736 }
737 
738 
739 /**
740  * Returns the resistance against the indicated damage type.
741  */
742 int movetype::resistances::resistance_against(const std::string & damage_type) const
743 {
744  return cfg_[damage_type].to_int(100);
745 }
746 
747 
748 /**
749  * Merges the given config over the existing costs.
750  * If @a overwrite is false, the new values will be added to the old.
751  */
752 void movetype::resistances::merge(const config & new_data, bool overwrite)
753 {
754  if ( overwrite )
755  // We do not support child tags here, so do not copy any that might
756  // be in the input. (If in the future we need to support child tags,
757  // change "merge_attributes" to "merge_with".)
758  cfg_.merge_attributes(new_data);
759  else
760  for (const config::attribute & a : new_data.attribute_range()) {
761  config::attribute_value & dest = cfg_[a.first];
762  dest = std::max(0, dest.to_int(100) + a.second.to_int(0));
763  }
764 }
765 
766 
767 /**
768  * Writes our data to a config, as a child if @a child_name is specified.
769  * (No child is created if there is no data.)
770  */
771 void movetype::resistances::write(config & out_cfg, const std::string & child_name) const
772 {
773  if ( cfg_.empty() )
774  return;
775 
776  if ( child_name.empty() )
777  out_cfg.merge_with(cfg_);
778  else
779  out_cfg.add_child(child_name, cfg_);
780 }
781 
782 
783 /* *** movetype *** */
784 
785 
786 /**
787  * Default constructor
788  */
790  movement_(mvj_params_, nullptr),
793  defense_(),
794  resist_(),
795  flying_(false)
796 {
797 }
798 
799 
800 /**
801  * Constructor from a config
802  */
804  movement_(cfg.child_or_empty("movement_costs"), mvj_params_, nullptr),
805  vision_(cfg.child_or_empty("vision_costs"), mvj_params_, &movement_),
806  jamming_(cfg.child_or_empty("jamming_costs"), mvj_params_, &vision_),
807  defense_(cfg.child_or_empty("defense")),
808  resist_(cfg.child_or_empty("resistance")),
809  flying_(cfg["flies"].to_bool(false))
810 {
811  // 1.15 will support both "flying" and "flies", with "flies" being deprecated
812  flying_ = cfg["flying"].to_bool(flying_);
813 }
814 
815 
816 /**
817  * Copy constructor
818  */
820  movement_(that.movement_, nullptr),
821  vision_(that.vision_, &movement_),
822  jamming_(that.jamming_, &vision_),
823  defense_(that.defense_),
824  resist_(that.resist_),
825  flying_(that.flying_)
826 {
827 }
828 
829 /**
830  * Move constructor.
831  */
833  movement_(std::move(that.movement_), nullptr),
834  vision_(std::move(that.vision_), &movement_),
835  jamming_(std::move(that.jamming_), &vision_),
836  defense_(std::move(that.defense_)),
837  resist_(std::move(that.resist_)),
838  flying_(std::move(that.flying_))
839 {
840 }
841 
842 /**
843  * Checks if we have a defense cap (nontrivial min value) for any of the given terrain types.
844  */
845 bool movetype::has_terrain_defense_caps(const std::set<t_translation::terrain_code> & ts) const {
846  for (const t_translation::terrain_code & t : ts) {
847  if (defense_.capped(t))
848  return true;
849  }
850  return false;
851 }
852 
853 /**
854  * Merges the given config over the existing data.
855  * If @a overwrite is false, the new values will be added to the old.
856  */
857 void movetype::merge(const config & new_cfg, bool overwrite)
858 {
859  for (const auto & applies_to : movetype::effects) {
860  for (const config & child : new_cfg.child_range(applies_to)) {
861  merge(child, applies_to, overwrite);
862  }
863  }
864 
865  // "flies" is used when WML defines a movetype.
866  // "flying" is used when WML defines a unit.
867  // It's easier to support both than to track which case we are in.
868  // Note: in 1.15 "flies" is deprecated, with "flying" preferred in movetype too.
869  flying_ = new_cfg["flies"].to_bool(flying_);
870  flying_ = new_cfg["flying"].to_bool(flying_);
871 }
872 
873 void movetype::merge(const config & new_cfg, const std::string & applies_to, bool overwrite)
874 {
875  if(applies_to == "movement_costs") {
876  movement_.merge(new_cfg, overwrite, {&vision_, &jamming_});
877  }
878  else if(applies_to == "vision_costs") {
879  vision_.merge(new_cfg, overwrite, {&jamming_});
880  }
881  else if(applies_to == "jamming_costs") {
882  jamming_.merge(new_cfg, overwrite, {});
883  }
884  else if(applies_to == "defense") {
885  defense_.merge(new_cfg, overwrite);
886  }
887  else if(applies_to == "resistance") {
888  resist_.merge(new_cfg, overwrite);
889  }
890 }
891 
892 /**
893  * The set of strings defining effects which apply to movetypes.
894  */
895 const std::set<std::string> movetype::effects {"movement_costs",
896  "vision_costs", "jamming_costs", "defense", "resistance"};
897 
898 /**
899  * Writes the movement type data to the provided config.
900  */
901 void movetype::write(config & cfg) const
902 {
903  movement_.write(cfg, "movement_costs", false);
904  vision_.write(cfg, "vision_costs", false);
905  jamming_.write(cfg, "jamming_costs", false);
906  defense_.write(cfg, "defense");
907  resist_.write(cfg, "resistance");
908 
909  if ( flying_ )
910  cfg["flying"] = true;
911 }
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
cache_t cache_
Cache of values based on the config.
Definition: movetype.cpp:140
parameters(int min, int max, int(*eval_fun)(int)=nullptr, bool move=true, bool high=false)
Whether we are looking for highest or lowest (unless inverted by the underlying terrain).
Definition: movetype.cpp:66
bool empty() const
Returns whether or not our data is empty.
Definition: movetype.cpp:532
config cfg_
Config describing the terrain values.
Definition: movetype.cpp:138
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:545
void merge(const config &new_values, bool overwrite)
Merges the given config over the existing costs.
Definition: movetype.cpp:190
std::map< std::string, t_string > string_map
void write(config &cfg, const std::string &child_name="", bool merged=true) const override
Writes our data to a config.
Definition: movetype.cpp:583
data(const parameters &params)
Constructor.
Definition: movetype.cpp:91
void swap_data(movetype::terrain_info &that)
Swap function for the terrain_info class.
Definition: movetype.cpp:480
const terrain_info *const fallback_
Definition: movetype.hpp:148
terrain_info jamming_
Definition: movetype.hpp:305
const ter_data_cache & terrain_types() const
std::map< t_translation::terrain_code, int > cache_t
Definition: movetype.cpp:135
movetype & operator=(const movetype &that)
Definition: movetype.cpp:516
std::unique_ptr< data > unique_data_
Definition: movetype.hpp:146
int max_value
The smallest allowable value.
Definition: movetype.cpp:58
Variant for storing WML attributes.
terrain_info(const parameters &params, const terrain_info *fallback)
Constructor.
Definition: movetype.cpp:396
#define a
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
Definition: movetype.hpp:155
movetype()
Default constructor.
Definition: movetype.cpp:789
child_itors child_range(config_key_type key)
Definition: config.cpp:362
data(const data &that)
Definition: movetype.cpp:102
attribute_map::value_type attribute
Definition: config.hpp:256
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
const data & get_data() const
Returns either *unique_data_ or *shared_data_, choosing the one that currently holds the data...
Definition: movetype.cpp:622
STL namespace.
void merge(const config &new_data, bool overwrite)
Merges the given config over the existing costs.
Definition: movetype.cpp:752
const std::string & type() const
Definition: attack_type.hpp:42
bool empty() const
Tests for no data in this object.
Definition: movetype.cpp:111
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:857
The basic "size" of the unit - flying, small land, large land, etc.
Definition: movetype.hpp:41
void write(config &cfg) const
Writes the movement type data to the provided config.
Definition: movetype.cpp:901
bool capped(const t_translation::terrain_code &terrain) const
Returns whether there is a defense cap associated to this terrain.
Definition: movetype.hpp:177
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:664
const_attr_itors attribute_range() const
Definition: config.cpp:809
void clear_cache() const
Clears the cached data (presumably our fallback has changed).
Definition: movetype.cpp:149
int resistance_against(const attack_type &attack) const
Returns the resistance against the indicated attack.
Definition: movetype.cpp:733
#define b
void merge_with(const config &c)
Merge config &#39;c&#39; into this config, overwriting this config&#39;s values.
Definition: config.cpp:1167
static game_config_manager * get()
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:643
bool use_move
Converter for values taken from a config. May be nullptr.
Definition: movetype.cpp:63
void write(config &out_cfg, const std::string &child_name) const
If there is data, writes it to the config.
Definition: movetype.cpp:226
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:771
std::unique_ptr< terrain_costs > make_standalone() const override
Does a sufficiently deep copy so that the returned object&#39;s lifespan is independent of other objects&#39;...
Definition: movetype.cpp:602
static const std::set< std::string > effects
The set of applicable effects for movement types.
Definition: movetype.hpp:297
const terrain_code MINUS
Stores a set of data based on terrain, in some cases with raw pointers to other instances of terrain_...
Definition: movetype.hpp:91
const terrain_code PLUS
int value(const t_translation::terrain_code &terrain) const override
Returns the value associated with the given terrain.
Definition: movetype.cpp:571
std::shared_ptr< const data > shared_data_
Definition: movetype.hpp:147
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:130
void merge(const config &new_data, bool overwrite)
Merges the given config over the existing costs.
Definition: movetype.cpp:706
std::string write_terrain_code(const terrain_code &tcode)
Writes a single terrain code to a string.
~terrain_info() override
Destructor.
int default_value
The largest allowable value.
Definition: movetype.cpp:59
bool high_is_good
Whether to look at underlying movement or defense terrains.
Definition: movetype.cpp:64
std::size_t i
Definition: function.cpp:933
bool config_has_changes(const config &new_values, bool overwrite) const
Tests if merging new_values would result in changes.
Definition: movetype.cpp:161
terrain_info movement_
Definition: movetype.hpp:303
bool flying_
Definition: movetype.hpp:309
static const terrain_info::parameters params_max_
Definition: movetype.hpp:161
const parameters & params_
Various parameters used when calculating values.
Definition: movetype.cpp:142
#define ERR_CF
Definition: movetype.cpp:31
config & add_child(config_key_type key)
Definition: config.cpp:476
int(* eval)(int)
The default value (if no data is available).
Definition: movetype.cpp:61
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, as happens when terrain_defense is copied, or 2) all of the siblings are being copied, as happens when movetype is copied.
Definition: movetype.cpp:466
#define WRN_CF
Definition: movetype.cpp:32
int calc_value(const t_translation::terrain_code &terrain, const terrain_info *fallback, unsigned recurse_count) const
Calculates the value associated with the given terrain.
Definition: movetype.cpp:266
void swap(movetype::terrain_defense &a, movetype::terrain_defense &b)
Swap function for the terrain_defense class.
Definition: movetype.cpp:493
static lg::log_domain log_config("config")
double t
Definition: astarsearch.cpp:64
utils::string_map damage_table() const
Returns a map from attack types to resistances.
Definition: movetype.cpp:718
resistances resist_
Definition: movetype.hpp:307
terrain_defense defense_
Definition: movetype.hpp:306
Standard logging facilities (interface).
std::vector< terrain_code > ter_list
Definition: translation.hpp:78
terrain_info vision_
Definition: movetype.hpp:304
static const terrain_info::parameters mvj_params_
Limits for movement, vision and jamming.
Definition: movetype.hpp:219
const parameters & params() const
Read-only access to our parameters.
Definition: movetype.cpp:115
The parameters used when calculating a terrain-based value.
Definition: movetype.cpp:55
friend void swap(movetype &a, movetype &b)
Swap function for the movetype class, including its terrain_info members.
Definition: movetype.cpp:506
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
terrain_defense & operator=(const terrain_defense &that)
Definition: movetype.cpp:691
static std::unique_ptr< terrain_costs > read_terrain_costs(const config &cfg)
Reverse of terrain_costs::write. Never returns nullptr.
Definition: movetype.cpp:422
Stores a set of defense levels.
Definition: movetype.hpp:158
static const terrain_info::parameters params_min_
Definition: movetype.hpp:160
bool empty() const
Definition: config.cpp:884
data(const config &cfg, const parameters &params)
Constructor.
Definition: movetype.cpp:96
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:845
int value(const t_translation::terrain_code &terrain, const terrain_info *fallback) const
Returns the value associated with the given terrain.
Definition: movetype.cpp:117
std::shared_ptr< terrain_type_data > ter_data_cache