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