The Battle for Wesnoth  1.15.0-dev
attack_type.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 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 unit-type specific attributes, animations, advancement.
18  */
19 
20 #include "units/attack_type.hpp"
21 
22 #include "formula/callable_objects.hpp"
23 #include "formula/formula.hpp"
25 #include "formula/string_utils.hpp"
26 #include "gettext.hpp"
27 #include "lexical_cast.hpp"
28 #include "log.hpp"
30 #include "utils/math.hpp"
31 
32 #include <cassert>
33 
34 static lg::log_domain log_config("config");
35 #define ERR_CF LOG_STREAM(err, log_config)
36 #define WRN_CF LOG_STREAM(warn, log_config)
37 #define LOG_CONFIG LOG_STREAM(info, log_config)
38 #define DBG_CF LOG_STREAM(debug, log_config)
39 
40 static lg::log_domain log_unit("unit");
41 #define DBG_UT LOG_STREAM(debug, log_unit)
42 #define ERR_UT LOG_STREAM(err, log_unit)
43 
45  : self_loc_()
46  , other_loc_()
47  , is_attacker_(false)
48  , other_attack_(nullptr)
49  , description_(cfg["description"].t_str())
50  , id_(cfg["name"])
51  , type_(cfg["type"])
52  , icon_(cfg["icon"])
53  , range_(cfg["range"])
54  , min_range_(cfg["min_range"].to_int(1))
55  , max_range_(cfg["max_range"].to_int(1))
56  , damage_(cfg["damage"])
57  , num_attacks_(cfg["number"])
58  , attack_weight_(cfg["attack_weight"].to_double(1.0))
59  , defense_weight_(cfg["defense_weight"].to_double(1.0))
60  , accuracy_(cfg["accuracy"])
61  , movement_used_(cfg["movement_used"].to_int(100000))
62  , parry_(cfg["parry"])
63  , specials_(cfg.child_or_empty("specials"))
64 {
65  if(description_.empty()) {
67  }
68 
69  if(icon_.empty()) {
70  if(!id_.empty()) {
71  icon_ = "attacks/" + id_ + ".png";
72  } else {
73  icon_ = "attacks/blank-attack.png";
74  }
75  }
76 }
77 
79 {
80  if(accuracy_ == 0 && parry_ == 0) {
81  return "";
82  }
83 
84  std::ostringstream s;
86 
87  if(parry_ != 0) {
88  s << "/" << utils::signed_percent(parry_);
89  }
90 
91  return s.str();
92 }
93 
94 /**
95  * Returns whether or not *this matches the given @a filter, ignoring the
96  * complexities introduced by [and], [or], and [not].
97  */
98 static bool matches_simple_filter(const attack_type& attack, const config& filter)
99 {
100  const std::vector<std::string>& filter_range = utils::split(filter["range"]);
101  const std::string& filter_damage = filter["damage"];
102  const std::string& filter_attacks = filter["number"];
103  const std::string& filter_accuracy = filter["accuracy"];
104  const std::string& filter_parry = filter["parry"];
105  const std::string& filter_movement = filter["movement_used"];
106  const std::vector<std::string> filter_name = utils::split(filter["name"]);
107  const std::vector<std::string> filter_type = utils::split(filter["type"]);
108  const std::vector<std::string> filter_special = utils::split(filter["special"]);
109  const std::vector<std::string> filter_special_active = utils::split(filter["special_active"]);
110  const std::string filter_formula = filter["formula"];
111 
112  if(!filter_range.empty() && std::find(filter_range.begin(), filter_range.end(), attack.range()) == filter_range.end()) {
113  return false;
114  }
115 
116  if(!filter_damage.empty() && !in_ranges(attack.damage(), utils::parse_ranges(filter_damage))) {
117  return false;
118  }
119 
120  if(!filter_attacks.empty() && !in_ranges(attack.num_attacks(), utils::parse_ranges(filter_attacks))) {
121  return false;
122  }
123 
124  if(!filter_accuracy.empty() && !in_ranges(attack.accuracy(), utils::parse_ranges(filter_accuracy))) {
125  return false;
126  }
127 
128  if(!filter_parry.empty() && !in_ranges(attack.parry(), utils::parse_ranges(filter_parry))) {
129  return false;
130  }
131 
132  if(!filter_movement.empty() && !in_ranges(attack.movement_used(), utils::parse_ranges(filter_movement))) {
133  return false;
134  }
135 
136  if(!filter_name.empty() && std::find(filter_name.begin(), filter_name.end(), attack.id()) == filter_name.end()) {
137  return false;
138  }
139 
140  if(!filter_type.empty() && std::find(filter_type.begin(), filter_type.end(), attack.type()) == filter_type.end()) {
141  return false;
142  }
143 
144  if(!filter_special.empty()) {
145  bool found = false;
146  for(auto& special : filter_special) {
147  if(attack.get_special_bool(special, true)) {
148  found = true;
149  break;
150  }
151  }
152 
153  if(!found) {
154  return false;
155  }
156  }
157 
158  if(!filter_special_active.empty()) {
159  bool found = false;
160  for(auto& special : filter_special_active) {
161  if(attack.get_special_bool(special, false)) {
162  found = true;
163  break;
164  }
165  }
166 
167  if(!found) {
168  return false;
169  }
170  }
171 
172  if(!filter_formula.empty()) {
173  try {
174  const wfl::attack_type_callable callable(attack);
175  const wfl::formula form(filter_formula, new wfl::gamestate_function_symbol_table);
176 
177  if(!form.evaluate(callable).as_bool()) {
178  return false;
179  }
180  } catch(const wfl::formula_error& e) {
181  lg::wml_error() << "Formula error in weapon filter: " << e.type << " at " << e.filename << ':' << e.line << ")\n";
182  // Formulae with syntax errors match nothing
183  return false;
184  }
185  }
186 
187  // Passed all tests.
188  return true;
189 }
190 
191 /**
192  * Returns whether or not *this matches the given @a filter.
193  */
194 bool attack_type::matches_filter(const config& filter) const
195 {
196  // Handle the basic filter.
197  bool matches = matches_simple_filter(*this, filter);
198 
199  // Handle [and], [or], and [not] with in-order precedence
200  for(const config::any_child& condition : filter.all_children_range()) {
201  // Handle [and]
202  if(condition.key == "and") {
203  matches = matches && matches_filter(condition.cfg);
204 
205  // Handle [or]
206  } else if(condition.key == "or") {
207  matches = matches || matches_filter(condition.cfg);
208 
209  // Handle [not]
210  } else if(condition.key == "not") {
211  matches = matches && !matches_filter(condition.cfg);
212  }
213  }
214 
215  return matches;
216 }
217 
218 /**
219  * Modifies *this using the specifications in @a cfg, but only if *this matches
220  * @a cfg viewed as a filter.
221  *
222  * @returns whether or not @c this matched the @a cfg as a filter.
223  */
225 {
226  if(!matches_filter(cfg)) {
227  return false;
228  }
229 
230  const std::string& set_name = cfg["set_name"];
231  const t_string& set_desc = cfg["set_description"];
232  const std::string& set_type = cfg["set_type"];
233  const std::string& set_range = cfg["set_range"];
234  const std::string& set_icon = cfg["set_icon"];
235  const std::string& del_specials = cfg["remove_specials"];
236  const config& set_specials = cfg.child("set_specials");
237  const std::string& increase_damage = cfg["increase_damage"];
238  const std::string& set_damage = cfg["set_damage"];
239  const std::string& increase_attacks = cfg["increase_attacks"];
240  const std::string& set_attacks = cfg["set_attacks"];
241  const std::string& set_attack_weight = cfg["attack_weight"];
242  const std::string& set_defense_weight = cfg["defense_weight"];
243  const std::string& increase_accuracy = cfg["increase_accuracy"];
244  const std::string& set_accuracy = cfg["set_accuracy"];
245  const std::string& increase_parry = cfg["increase_parry"];
246  const std::string& set_parry = cfg["set_parry"];
247  const std::string& increase_movement = cfg["increase_movement_used"];
248  const std::string& set_movement = cfg["set_movement_used"];
249  // NB: If you add something here that requires a description,
250  // it needs to be added to describe_modification as well.
251 
252  if(set_name.empty() == false) {
253  id_ = set_name;
254  }
255 
256  if(set_desc.empty() == false) {
257  description_ = set_desc;
258  }
259 
260  if(set_type.empty() == false) {
261  type_ = set_type;
262  }
263 
264  if(set_range.empty() == false) {
265  range_ = set_range;
266  }
267 
268  if(set_icon.empty() == false) {
269  icon_ = set_icon;
270  }
271 
272  if(del_specials.empty() == false) {
273  const std::vector<std::string>& dsl = utils::split(del_specials);
274  config new_specials;
275 
276  for(const config::any_child& vp : specials_.all_children_range()) {
277  std::vector<std::string>::const_iterator found_id = std::find(dsl.begin(), dsl.end(), vp.cfg["id"].str());
278  if(found_id == dsl.end()) {
279  new_specials.add_child(vp.key, vp.cfg);
280  }
281  }
282 
283  specials_ = new_specials;
284  }
285 
286  if(set_specials) {
287  const std::string& mode = set_specials["mode"];
288  if(mode != "append") {
289  specials_.clear();
290  }
291 
292  for(const config::any_child& value : set_specials.all_children_range()) {
293  specials_.add_child(value.key, value.cfg);
294  }
295  }
296 
297  if(set_damage.empty() == false) {
298  damage_ = std::stoi(set_damage);
299  if(damage_ < 0) {
300  damage_ = 0;
301  }
302  }
303 
304  if(increase_damage.empty() == false) {
305  damage_ = utils::apply_modifier(damage_, increase_damage);
306  if(damage_ < 0) {
307  damage_ = 0;
308  }
309  }
310 
311  if(set_attacks.empty() == false) {
312  num_attacks_ = std::stoi(set_attacks);
313  if(num_attacks_ < 0) {
314  num_attacks_ = 0;
315  }
316  }
317 
318  if(increase_attacks.empty() == false) {
319  num_attacks_ = utils::apply_modifier(num_attacks_, increase_attacks, 1);
320  }
321 
322  if(set_accuracy.empty() == false) {
323  accuracy_ = std::stoi(set_accuracy);
324  }
325 
326  if(increase_accuracy.empty() == false) {
327  accuracy_ = utils::apply_modifier(accuracy_, increase_accuracy);
328  }
329 
330  if(set_parry.empty() == false) {
331  parry_ = std::stoi(set_parry);
332  }
333 
334  if(increase_parry.empty() == false) {
335  parry_ = utils::apply_modifier(parry_, increase_parry);
336  }
337 
338  if(set_movement.empty() == false) {
339  movement_used_ = std::stoi(set_movement);
340  }
341 
342  if(increase_movement.empty() == false) {
343  movement_used_ = utils::apply_modifier(movement_used_, increase_movement, 1);
344  }
345 
346  if(set_attack_weight.empty() == false) {
347  attack_weight_ = lexical_cast_default<double>(set_attack_weight, 1.0);
348  }
349 
350  if(set_defense_weight.empty() == false) {
351  defense_weight_ = lexical_cast_default<double>(set_defense_weight, 1.0);
352  }
353 
354  return true;
355 }
356 
357 /**
358  * Trimmed down version of apply_modification(), with no modifications actually
359  * made. This can be used to get a description of the modification(s) specified
360  * by @a cfg (if *this matches cfg as a filter).
361  *
362  * If *description is provided, it will be set to a (translated) description
363  * of the modification(s) applied (currently only changes to the number of
364  * strikes, damage, accuracy, and parry are included in this description).
365  *
366  * @returns whether or not @c this matched the @a cfg as a filter.
367  */
368 bool attack_type::describe_modification(const config& cfg, std::string* description)
369 {
370  if(!matches_filter(cfg))
371  return false;
372 
373  // Did the caller want the description?
374  if(description != nullptr) {
375  const std::string& increase_damage = cfg["increase_damage"];
376  const std::string& set_damage = cfg["set_damage"];
377  const std::string& increase_attacks = cfg["increase_attacks"];
378  const std::string& set_attacks = cfg["set_attacks"];
379  const std::string& increase_accuracy = cfg["increase_accuracy"];
380  const std::string& set_accuracy = cfg["set_accuracy"];
381  const std::string& increase_parry = cfg["increase_parry"];
382  const std::string& set_parry = cfg["set_parry"];
383  const std::string& increase_movement = cfg["increase_movement_used"];
384  const std::string& set_movement = cfg["set_movement_used"];
385 
386  std::vector<t_string> desc;
387 
388  if(!increase_damage.empty()) {
389  desc.emplace_back(VNGETTEXT(
390  // TRANSLATORS: Current value for WML code increase_damage, documented in https://wiki.wesnoth.org/EffectWML
391  "<span color=\"$color\">$number_or_percent</span> damage",
392  "<span color=\"$color\">$number_or_percent</span> damage",
393  std::stoi(increase_damage),
394  {{"number_or_percent", utils::print_modifier(increase_damage)}, {"color", increase_damage[0] == '-' ? "red" : "green"}}));
395  }
396 
397  if(!set_damage.empty()) {
398  // TRANSLATORS: Current value for WML code set_damage, documented in https://wiki.wesnoth.org/EffectWML
399  desc.emplace_back(VNGETTEXT(
400  "$number damage",
401  "$number damage",
402  std::stoi(set_damage),
403  {{"number", set_damage}}));
404  }
405 
406  if(!increase_attacks.empty()) {
407  desc.emplace_back(VNGETTEXT(
408  // TRANSLATORS: Current value for WML code increase_attacks, documented in https://wiki.wesnoth.org/EffectWML
409  "<span color=\"$color\">$number_or_percent</span> strike",
410  "<span color=\"$color\">$number_or_percent</span> strikes",
411  std::stoi(increase_attacks),
412  {{"number_or_percent", utils::print_modifier(increase_attacks)}, {"color", increase_attacks[0] == '-' ? "red" : "green"}}));
413  }
414 
415  if(!set_attacks.empty()) {
416  desc.emplace_back(VNGETTEXT(
417  // TRANSLATORS: Current value for WML code set_attacks, documented in https://wiki.wesnoth.org/EffectWML
418  "$number strike",
419  "$number strikes",
420  std::stoi(set_attacks),
421  {{"number", set_attacks}}));
422  }
423 
424  if(!set_accuracy.empty()) {
425  desc.emplace_back(VGETTEXT(
426  // TRANSLATORS: Current value for WML code set_accuracy, documented in https://wiki.wesnoth.org/EffectWML
427  "$number| accuracy",
428  {{"number", set_accuracy}}));
429  }
430 
431  if(!increase_accuracy.empty()) {
432  desc.emplace_back(VGETTEXT(
433  // TRANSLATORS: Current value for WML code increase_accuracy, documented in https://wiki.wesnoth.org/EffectWML
434  "<span color=\"$color\">$number_or_percent|%</span> accuracy",
435  {{"number_or_percent", utils::print_modifier(increase_accuracy)}, {"color", increase_accuracy[0] == '-' ? "red" : "green"}}));
436  }
437 
438  if(!set_parry.empty()) {
439  desc.emplace_back(VGETTEXT(
440  // TRANSLATORS: Current value for WML code set_parry, documented in https://wiki.wesnoth.org/EffectWML
441  "$number parry",
442  {{"number", set_parry}}));
443  }
444 
445  if(!increase_parry.empty()) {
446  desc.emplace_back(VGETTEXT(
447  // TRANSLATORS: Current value for WML code increase_parry, documented in https://wiki.wesnoth.org/EffectWML
448  "<span color=\"$color\">$number_or_percent</span> parry",
449  {{"number_or_percent", utils::print_modifier(increase_parry)}, {"color", increase_parry[0] == '-' ? "red" : "green"}}));
450  }
451 
452  if(!set_movement.empty()) {
453  desc.emplace_back(VNGETTEXT(
454  // TRANSLATORS: Current value for WML code set_movement_used, documented in https://wiki.wesnoth.org/EffectWML
455  "$number movement point",
456  "$number movement points",
457  std::stoi(set_movement),
458  {{"number", set_movement}}));
459  }
460 
461  if(!increase_movement.empty()) {
462  desc.emplace_back(VNGETTEXT(
463  // TRANSLATORS: Current value for WML code increase_movement_used, documented in https://wiki.wesnoth.org/EffectWML
464  "<span color=\"$color\">$number_or_percent</span> movement point",
465  "<span color=\"$color\">$number_or_percent</span> movement points",
466  std::stoi(increase_movement),
467  {{"number_or_percent", utils::print_modifier(increase_movement)}, {"color", increase_movement[0] == '-' ? "red" : "green"}}));
468  }
469 
470  *description = utils::format_conjunct_list("", desc);
471  }
472 
473  return true;
474 }
475 
476 void attack_type::write(config& cfg) const
477 {
478  cfg["description"] = description_;
479  cfg["name"] = id_;
480  cfg["type"] = type_;
481  cfg["icon"] = icon_;
482  cfg["range"] = range_;
483  cfg["min_range"] = min_range_;
484  cfg["max_range"] = max_range_;
485  cfg["damage"] = damage_;
486  cfg["number"] = num_attacks_;
487  cfg["attack_weight"] = attack_weight_;
488  cfg["defense_weight"] = defense_weight_;
489  cfg["accuracy"] = accuracy_;
490  cfg["movement_used"] = movement_used_;
491  cfg["parry"] = parry_;
492  cfg.add_child("specials", specials_);
493 }
494 
495 /**
496  * Sets the context under which specials will be checked for being active.
497  * This version is appropriate if both units in a combat are known.
498  * @param[in] self A reference to the unit with this weapon.
499  * @param[in] other A reference to the other unit in the combat.
500  * @param[in] unit_loc The location of the unit with this weapon.
501  * @param[in] other_loc The location of the other unit in the combat.
502  * @param[in] attacking Whether or not the unit with this weapon is the attacker.
503  * @param[in] other_attack The attack used by the other unit.
504  */
506  const_attack_ptr other_attack,
507  unit_const_ptr self,
508  unit_const_ptr other,
509  const map_location& unit_loc,
510  const map_location& other_loc,
511  bool attacking)
512  : parent(weapon.shared_from_this())
513 {
514  weapon.self_ = self;
515  weapon.other_ = other;
516  weapon.self_loc_ = unit_loc;
517  weapon.other_loc_ = other_loc;
518  weapon.is_attacker_ = attacking;
519  weapon.other_attack_ = other_attack;
520  weapon.is_for_listing_ = false;
521 }
522 
523 /**
524  * Sets the context under which specials will be checked for being active.
525  * This version is appropriate if there is no specific combat being considered.
526  * @param[in] self A reference to the unit with this weapon.
527  * @param[in] loc The location of the unit with this weapon.
528  * @param[in] attacking Whether or not the unit with this weapon is the attacker.
529  */
531  const attack_type& weapon, unit_const_ptr self, const map_location& loc, bool attacking)
532  : parent(weapon.shared_from_this())
533 {
534  weapon.self_ = self;
535  weapon.other_ = nullptr;
536  weapon.self_loc_ = loc;
538  weapon.is_attacker_ = attacking;
539  weapon.other_attack_ = nullptr;
540  weapon.is_for_listing_ = false;
541 }
542 
543 /**
544  * Sets the context under which specials will be checked for being active.
545  * This version is appropriate for theoretical units of a particular type.
546  * @param[in] self_type A reference to the type of the unit with this weapon.
547  * @param[in] loc The location of the unit with this weapon.
548  * @param[in] attacking Whether or not the unit with this weapon is the attacker.
549  */
551  const attack_type& weapon, const unit_type& self_type, const map_location& loc, bool attacking)
552  : parent(weapon.shared_from_this())
553 {
554  UNUSED(self_type);
555  weapon.self_ = nullptr;
556  weapon.other_ = nullptr;
557  weapon.self_loc_ = loc;
559  weapon.is_attacker_ = attacking;
560  weapon.other_attack_ = nullptr;
561  weapon.is_for_listing_ = false;
562 }
563 
565  : parent(weapon.shared_from_this())
566 {
567  weapon.is_for_listing_ = true;
568  weapon.is_attacker_ = attacking;
569 }
570 
572 {
573  if(was_moved) {
574  return;
575  }
576 
577  parent->self_ = nullptr;
578  parent->other_ = nullptr;
579  parent->self_loc_ = map_location::null_location();
580  parent->other_loc_ = map_location::null_location();
581  parent->is_attacker_ = false;
582  parent->other_attack_ = nullptr;
583  parent->is_for_listing_ = false;
584 }
585 
587  : parent(other.parent)
588 {
589  other.was_moved = true;
590 }
boost::intrusive_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:30
bool apply_modification(const config &cfg)
Modifies *this using the specifications in cfg, but only if *this matches cfg viewed as a filter...
std::string icon_
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:423
const std::string & id() const
Definition: attack_type.hpp:41
std::string format_conjunct_list(const t_string &empty, const std::vector< t_string > &elems)
Format a conjunctive list.
std::string type_
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:874
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:39
attack_type(const config &cfg)
Definition: attack_type.cpp:44
std::string filename
Definition: formula.hpp:107
New lexcical_cast header.
map_location other_loc_
int parry() const
Definition: attack_type.hpp:49
static lg::log_domain log_unit("unit")
bool in_ranges(const Cmp c, const std::vector< std::pair< Cmp, Cmp >> &ranges)
Definition: math.hpp:66
#define VNGETTEXT(msgid, msgid_plural, count,...)
unit_const_ptr other_
const std::string & type() const
Definition: attack_type.hpp:42
void clear()
Definition: config.cpp:816
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
int num_attacks() const
Definition: attack_type.hpp:51
A single unit type that the player may recruit.
Definition: types.hpp:42
double defense_weight_
static bool matches_simple_filter(const attack_type &attack, const config &filter)
Returns whether or not *this matches the given filter, ignoring the complexities introduced by [and]...
Definition: attack_type.cpp:98
void set_name(const t_string &value)
Definition: attack_type.hpp:56
int movement_used() const
Definition: attack_type.hpp:89
bool get_special_bool(const std::string &special, bool simple_check=false) const
Returns whether or not *this has a special with a tag or id equal to special.
Definition: abilities.cpp:642
std::vector< std::pair< int, int > > parse_ranges(const std::string &str)
specials_context_t(const attack_type &weapon, bool attacking)
Initialize weapon specials context for listing.
double attack_weight_
std::string type
Definition: formula.hpp:105
bool matches_filter(const config &filter) const
Returns whether or not *this matches the given filter.
std::string range_
General math utility functions.
const std::string & range() const
Definition: attack_type.hpp:44
config specials_
std::string egettext(char const *msgid)
Definition: gettext.cpp:398
void set_defense_weight(double value)
Definition: attack_type.hpp:66
void set_specials(config value)
Definition: attack_type.hpp:67
t_string description_
Encapsulates the map of the game.
Definition: location.hpp:42
#define UNUSED(x)
Definition: global.hpp:34
void set_damage(int value)
Definition: attack_type.hpp:63
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:269
bool is_for_listing_
int damage() const
Definition: attack_type.hpp:50
int accuracy() const
Definition: attack_type.hpp:48
static map_location::DIRECTION s
void write(config &cfg) const
std::string signed_percent(int val)
Convert into a percentage (using the Unicode "−" and +0% convention.
std::string accuracy_parry_description() const
Definition: attack_type.cpp:78
unit_const_ptr self_
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
config & add_child(config_key_type key)
Definition: config.cpp:479
bool describe_modification(const config &cfg, std::string *description)
Trimmed down version of apply_modification(), with no modifications actually made.
void set_range(const std::string &value)
Definition: attack_type.hpp:60
void set_parry(int value)
Definition: attack_type.hpp:62
std::string id_
bool empty() const
Definition: tstring.hpp:182
int apply_modifier(const int number, const std::string &amount, const int minimum)
const_attack_ptr other_attack_
void set_icon(const std::string &value)
Definition: attack_type.hpp:59
Standard logging facilities (interface).
static const map_location & null_location()
Definition: location.hpp:85
#define e
bool as_bool() const
Returns a boolean state of the variant value.
Definition: variant.cpp:320
std::shared_ptr< const attack_type > parent
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
std::shared_ptr< const attack_type > const_attack_ptr
Definition: ptr.hpp:37
std::string print_modifier(const std::string &mod)
Add a "+" or replace the "-" par Unicode minus.
void set_accuracy(int value)
Definition: attack_type.hpp:61
map_location self_loc_
void set_attack_weight(double value)
Definition: attack_type.hpp:65
static lg::log_domain log_config("config")
void set_type(const std::string &value)
Definition: attack_type.hpp:58