The Battle for Wesnoth  1.15.12+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_);
521 }
522 
524 {
525  movetype m(that);
526  swap(*this, m);
527  return *this;
528 }
529 
531 {
532  swap(*this, that);
533  return *this;
534 }
535 
536 /**
537  * Returns whether or not our data is empty.
538  */
540 {
541  return get_data().empty();
542 }
543 
544 
545 /**
546  * Merges the given config over the existing values.
547  * @param[in] new_values The new values.
548  * @param[in] overwrite If true, the new values overwrite the old.
549  * If false, the new values are added to the old.
550  * @param[in] dependants Other instances that use this as a fallback.
551  */
552 void movetype::terrain_info::merge(const config & new_values, bool overwrite,
553  const std::vector<movetype::terrain_info * > & dependants)
554 {
555  if ( !get_data().config_has_changes(new_values, overwrite) )
556  // Nothing will change, so skip the copy-on-write.
557  return;
558 
559  // Copy-on-write.
560  //
561  // We also need to make our cascade writeable, because changes to this
562  // instance will change data that they receive when using this as their
563  // fallback. However, it's no problem for a writable instance to have a
564  // shareable instance as its fallback.
566  for (auto & dependant : dependants) {
567  // This will automatically clear the dependant's cache
568  dependant->make_data_writable();
569  }
570 
571  unique_data_->merge(new_values, overwrite);
572 }
573 
574 
575 /**
576  * Returns the value associated with the given terrain.
577  */
579 {
580  return get_data().value(terrain, fallback_);
581 }
582 
583 /**
584  * Writes our data to a config.
585  * @param[out] cfg The config that will receive the data.
586  * @param[in] child_name If not empty, create and write to a child config with this tag.
587  * @param[in] merged If true, our data will be merged with our fallback's, and it is possible an empty child will be created.
588  * If false, data will not be merged, and an empty child will not be created.
589  */
590 void movetype::terrain_info::write(config & cfg, const std::string & child_name,
591  bool merged) const
592 {
593  if ( !merged )
594  get_data().write(cfg, child_name);
595  else
596  get_data().write(cfg, child_name, fallback_);
597 }
598 
599 
600 /**
601  * Does a sufficiently deep copy so that the returned object's lifespan
602  * is independent of other objects' lifespan. Never returns nullptr.
603  *
604  * This implements terrain_costs's virtual method for getting an instance that
605  * doesn't depend on the lifespan of a terrain_defense or movetype object.
606  * This will do a deep copy of the data (with fallback_ already merged) if
607  * needed.
608  */
609 std::unique_ptr<movetype::terrain_costs> movetype::terrain_info::make_standalone() const
610 {
611  std::unique_ptr<terrain_costs> t;
612  if(!fallback_) {
613  // Call the copy constructor, which will make_data_shareable().
614  t = std::make_unique<terrain_info>(*this, nullptr);
615  }
616  else if(get_data().empty()) {
617  // Pure fallback.
618  t = fallback_->make_standalone();
619  }
620  else {
621  // Need to merge data.
622  config merged;
623  write(merged, "", true);
624  t = std::make_unique<terrain_info>(merged, get_data().params(), nullptr);
625  }
626  return t;
627 }
628 
630 {
631  assert(unique_data_ || shared_data_);
632  assert(! (unique_data_ && shared_data_));
633  if(unique_data_)
634  return *unique_data_;
635  return *shared_data_;
636 }
637 
638 /**
639  * Copy the immutable data back to unique_data_, no-op if the data
640  * is already in unique_data_.
641  *
642  * Ensures our data is not shared, and therefore that changes only
643  * affect this instance of terrain_info (and any instances using it
644  * as a fallback).
645  *
646  * This does not need to affect the fallback - it's no problem if a
647  * writable instance has a fallback to a shareable instance, although
648  * a shareable instance must not fallback to a writable instance.
649  */
651 {
652  if(!unique_data_)
653  {
654  // Const hack because this is not really changing the data.
655  auto t = const_cast<terrain_info *>(this);
656  t->unique_data_.reset(new data(*shared_data_));
657  t->shared_data_.reset();
658  }
659 
660  // As we're about to write data, invalidate the cache
661  unique_data_->clear_cache();
662 }
663 
664 /**
665  * Move data to an immutable copy in shared_data_, no-op if the data
666  * is already in shared_data_.
667  *
668  * This is recursive on the fallback chain, because if the data shouldn't be
669  * writable then the data shouldn't be writable via the fallback either.
670  */
672 {
673  if(!unique_data_)
674  return;
675 
676  if(fallback_)
678 
679  // Const hack because this is not really changing the data.
680  auto t = const_cast<terrain_info *>(this);
681  t->shared_data_ = std::move(t->unique_data_);
682 }
683 
684 /* *** terrain_defense *** */
685 
687  min_(that.min_, nullptr),
688  max_(that.max_, nullptr)
689 {
690 }
691 
693  min_(std::move(that.min_), nullptr),
694  max_(std::move(that.max_), nullptr)
695 {
696 }
697 
699 {
700  min_.copy_data(that.min_);
701  max_.copy_data(that.max_);
702  return *this;
703 }
704 
706 {
707  min_.swap_data(that.min_);
708  max_.swap_data(that.max_);
709  return *this;
710 }
711 /**
712  * Merges the given config over the existing costs.
713  * (Not overwriting implies adding.)
714  */
715 void movetype::terrain_defense::merge(const config & new_data, bool overwrite)
716 {
717  min_.merge(new_data, overwrite, {});
718  max_.merge(new_data, overwrite, {});
719 }
720 
721 /* *** resistances *** */
722 
723 
724 /**
725  * Returns a map from attack types to resistances.
726  */
728 {
729  utils::string_map result;
730 
731  for (const config::attribute & attrb : cfg_.attribute_range()) {
732  result[attrb.first] = attrb.second;
733  }
734 
735  return result;
736 }
737 
738 
739 /**
740  * Returns the resistance against the indicated attack.
741  */
743 {
744  return cfg_[attack.type()].to_int(100);
745 }
746 
747 
748 /**
749  * Returns the resistance against the indicated damage type.
750  */
751 int movetype::resistances::resistance_against(const std::string & damage_type) const
752 {
753  return cfg_[damage_type].to_int(100);
754 }
755 
756 
757 /**
758  * Merges the given config over the existing costs.
759  * If @a overwrite is false, the new values will be added to the old.
760  */
761 void movetype::resistances::merge(const config & new_data, bool overwrite)
762 {
763  if ( overwrite )
764  // We do not support child tags here, so do not copy any that might
765  // be in the input. (If in the future we need to support child tags,
766  // change "merge_attributes" to "merge_with".)
767  cfg_.merge_attributes(new_data);
768  else
769  for (const config::attribute & a : new_data.attribute_range()) {
770  config::attribute_value & dest = cfg_[a.first];
771  dest = std::max(0, dest.to_int(100) + a.second.to_int(0));
772  }
773 }
774 
775 
776 /**
777  * Writes our data to a config, as a child if @a child_name is specified.
778  * (No child is created if there is no data.)
779  */
780 void movetype::resistances::write(config & out_cfg, const std::string & child_name) const
781 {
782  if ( cfg_.empty() )
783  return;
784 
785  if ( child_name.empty() )
786  out_cfg.merge_with(cfg_);
787  else
788  out_cfg.add_child(child_name, cfg_);
789 }
790 
791 
792 /* *** movetype *** */
793 
794 
795 /**
796  * Default constructor
797  */
799  movement_(mvj_params_, nullptr),
802  defense_(),
803  resist_(),
804  flying_(false)
805 {
806 }
807 
808 
809 /**
810  * Constructor from a config
811  */
813  movement_(cfg.child_or_empty("movement_costs"), mvj_params_, nullptr),
814  vision_(cfg.child_or_empty("vision_costs"), mvj_params_, &movement_),
815  jamming_(cfg.child_or_empty("jamming_costs"), mvj_params_, &vision_),
816  defense_(cfg.child_or_empty("defense")),
817  resist_(cfg.child_or_empty("resistance")),
818  flying_(cfg["flies"].to_bool(false))
819 {
820  // 1.15 will support both "flying" and "flies", with "flies" being deprecated
821  flying_ = cfg["flying"].to_bool(flying_);
822 }
823 
824 
825 /**
826  * Copy constructor
827  */
829  movement_(that.movement_, nullptr),
830  vision_(that.vision_, &movement_),
831  jamming_(that.jamming_, &vision_),
832  defense_(that.defense_),
833  resist_(that.resist_),
834  flying_(that.flying_)
835 {
836 }
837 
838 /**
839  * Move constructor.
840  */
842  movement_(std::move(that.movement_), nullptr),
843  vision_(std::move(that.vision_), &movement_),
844  jamming_(std::move(that.jamming_), &vision_),
845  defense_(std::move(that.defense_)),
846  resist_(std::move(that.resist_)),
847  flying_(std::move(that.flying_))
848 {
849 }
850 
851 /**
852  * Checks if we have a defense cap (nontrivial min value) for any of the given terrain types.
853  */
854 bool movetype::has_terrain_defense_caps(const std::set<t_translation::terrain_code> & ts) const {
855  for (const t_translation::terrain_code & t : ts) {
856  if (defense_.capped(t))
857  return true;
858  }
859  return false;
860 }
861 
862 /**
863  * Merges the given config over the existing data.
864  * If @a overwrite is false, the new values will be added to the old.
865  */
866 void movetype::merge(const config & new_cfg, bool overwrite)
867 {
868  for (const auto & applies_to : movetype::effects) {
869  for (const config & child : new_cfg.child_range(applies_to)) {
870  merge(child, applies_to, overwrite);
871  }
872  }
873 
874  // "flies" is used when WML defines a movetype.
875  // "flying" is used when WML defines a unit.
876  // It's easier to support both than to track which case we are in.
877  // Note: in 1.15 "flies" is deprecated, with "flying" preferred in movetype too.
878  flying_ = new_cfg["flies"].to_bool(flying_);
879  flying_ = new_cfg["flying"].to_bool(flying_);
880 }
881 
882 void movetype::merge(const config & new_cfg, const std::string & applies_to, bool overwrite)
883 {
884  if(applies_to == "movement_costs") {
885  movement_.merge(new_cfg, overwrite, {&vision_, &jamming_});
886  }
887  else if(applies_to == "vision_costs") {
888  vision_.merge(new_cfg, overwrite, {&jamming_});
889  }
890  else if(applies_to == "jamming_costs") {
891  jamming_.merge(new_cfg, overwrite, {});
892  }
893  else if(applies_to == "defense") {
894  defense_.merge(new_cfg, overwrite);
895  }
896  else if(applies_to == "resistance") {
897  resist_.merge(new_cfg, overwrite);
898  }
899  else {
900  ERR_CF << "movetype::merge with unknown applies_to: " << applies_to << std::endl;
901  }
902 }
903 
904 /**
905  * The set of strings defining effects which apply to movetypes.
906  */
907 const std::set<std::string> movetype::effects {"movement_costs",
908  "vision_costs", "jamming_costs", "defense", "resistance"};
909 
910 /**
911  * Writes the movement type data to the provided config.
912  */
913 void movetype::write(config & cfg) const
914 {
915  movement_.write(cfg, "movement_costs", false);
916  vision_.write(cfg, "vision_costs", false);
917  jamming_.write(cfg, "jamming_costs", false);
918  defense_.write(cfg, "defense");
919  resist_.write(cfg, "resistance");
920 
921  if ( flying_ )
922  cfg["flying"] = true;
923 }
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:539
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:552
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:590
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:333
std::map< t_translation::terrain_code, int > cache_t
Definition: movetype.cpp:144
movetype & operator=(const movetype &that)
Definition: movetype.cpp:523
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:798
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:629
STL namespace.
void merge(const config &new_data, bool overwrite)
Merges the given config over the existing costs.
Definition: movetype.cpp:761
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:866
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:913
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:671
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:742
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:650
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:780
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:609
static const std::set< std::string > effects
The set of applicable effects for movement types.
Definition: movetype.hpp:325
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:578
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:715
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:331
bool flying_
Definition: movetype.hpp:337
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:727
resistances resist_
Definition: movetype.hpp:335
terrain_defense defense_
Definition: movetype.hpp:334
Standard logging facilities (interface).
std::vector< terrain_code > ter_list
Definition: translation.hpp:77
terrain_info vision_
Definition: movetype.hpp:332
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:698
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
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:854
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