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