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