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 #pragma once 16 17 #include "units/id.hpp" 18 #include "units/ptr.hpp" 19 #include "units/types.hpp" 20 21 #include "utils/type_trait_aliases.hpp" 22 23 #include <bitset> 24 #include <boost/dynamic_bitset_fwd.hpp> 25 #include <boost/ptr_container/ptr_vector.hpp> 26 #include <boost/variant.hpp> 27 28 class display; 29 class display_context; 30 class team; 31 class unit_animation_component; 32 class unit_formula_manager; 33 class vconfig; 34 struct color_t; 35 36 namespace unit_detail 37 { 38 template<typename T> get_or_default(const std::unique_ptr<T> & v)39 const T& get_or_default(const std::unique_ptr<T>& v) 40 { 41 if(v) { 42 return *v; 43 } else { 44 static const T def; 45 return def; 46 } 47 } 48 } 49 50 // Data typedef for unit_ability_list. 51 using unit_ability = std::pair<const config*, map_location>; 52 53 class unit_ability_list 54 { 55 public: unit_ability_list(const map_location & loc=map_location ())56 unit_ability_list(const map_location& loc = map_location()) : cfgs_() , loc_(loc) {} 57 58 // Implemented in unit_abilities.cpp highest(const std::string & key,int def=0) const59 std::pair<int, map_location> highest(const std::string& key, int def=0) const 60 { 61 return get_extremum(key, def, std::less<int>()); 62 } lowest(const std::string & key,int def=0) const63 std::pair<int, map_location> lowest(const std::string& key, int def=0) const 64 { 65 return get_extremum(key, def, std::greater<int>()); 66 } 67 68 template<typename TComp> 69 std::pair<int, map_location> get_extremum(const std::string& key, int def, const TComp& comp) const; 70 71 // The following make this class usable with standard library algorithms and such 72 typedef std::vector<unit_ability>::iterator iterator; 73 typedef std::vector<unit_ability>::const_iterator const_iterator; 74 begin()75 iterator begin() { return cfgs_.begin(); } begin() const76 const_iterator begin() const { return cfgs_.begin(); } end()77 iterator end() { return cfgs_.end(); } end() const78 const_iterator end() const { return cfgs_.end(); } 79 80 // Vector access empty() const81 bool empty() const { return cfgs_.empty(); } front()82 unit_ability& front() { return cfgs_.front(); } front() const83 const unit_ability& front() const { return cfgs_.front(); } back()84 unit_ability& back() { return cfgs_.back(); } back() const85 const unit_ability& back() const { return cfgs_.back(); } 86 erase(const iterator & erase_it)87 iterator erase(const iterator& erase_it) { return cfgs_.erase(erase_it); } push_back(const unit_ability & ability)88 void push_back(const unit_ability& ability) { cfgs_.push_back(ability); } 89 loc() const90 const map_location& loc() const { return loc_; } 91 private: 92 // Data 93 std::vector<unit_ability> cfgs_; 94 map_location loc_; 95 }; 96 97 /** 98 * This class represents a *single* unit of a specific type. 99 */ 100 class unit 101 { 102 public: 103 /** 104 * Clear this unit status cache for all units. Currently only the hidden 105 * status of units is cached this way. 106 */ 107 static void clear_status_caches(); 108 109 /** The path to the leader crown overlay. */ 110 static const std::string& leader_crown(); 111 private: 112 void init(const config& cfg, bool use_traits = false, const vconfig* vcfg = nullptr); 113 114 void init(const unit_type& t, int side, bool real_unit, unit_race::GENDER gender = unit_race::NUM_GENDERS); 115 116 // Copy constructor 117 unit(const unit& u); 118 119 unit(); 120 121 public: 122 /** Initializes a unit from a config */ create(const config & cfg,bool use_traits=false,const vconfig * vcfg=nullptr)123 static unit_ptr create(const config& cfg, bool use_traits = false, const vconfig* vcfg = nullptr) 124 { 125 unit_ptr res(new unit()); 126 res->init(cfg, use_traits, vcfg); 127 return res; 128 } 129 130 /** 131 * Initializes a unit from a unit type. 132 * 133 * Only real_unit-s should have random traits, name and gender (to prevent OOS caused by RNG calls) 134 */ create(const unit_type & t,int side,bool real_unit,unit_race::GENDER gender=unit_race::NUM_GENDERS)135 static unit_ptr create(const unit_type& t, int side, bool real_unit, unit_race::GENDER gender = unit_race::NUM_GENDERS) 136 { 137 unit_ptr res(new unit()); 138 res->init(t, side, real_unit, gender); 139 return res; 140 } 141 clone() const142 unit_ptr clone() const 143 { 144 return unit_ptr(new unit(*this)); 145 } 146 147 virtual ~unit(); 148 149 void swap(unit&); 150 151 unit& operator=(const unit&) = delete; 152 153 /** 154 * @defgroup unit_advance Advancement functions 155 * @{ 156 */ 157 158 /** Advances this unit to another type */ 159 void advance_to(const unit_type& t, bool use_traits = false); 160 161 /** 162 * Gets the possible types this unit can advance to on level-up. 163 * 164 * @returns A list of type IDs this unit may advance to. 165 */ advances_to() const166 const std::vector<std::string>& advances_to() const 167 { 168 return advances_to_; 169 } 170 171 /** 172 * Gets the names of the possible types this unit can advance to on level-up. 173 * 174 * @returns A list of the names of the types this unit may advance to. 175 */ 176 const std::vector<std::string> advances_to_translated() const; 177 178 /** 179 * Sets this unit's advancement options. 180 * 181 * @param advances_to A list of new type IDs this unit may advance to. 182 */ 183 void set_advances_to(const std::vector<std::string>& advances_to); 184 185 /** 186 * Checks whether this unit has any options to advance to. 187 * 188 * This considers both whether it has types to advance to OR whether any modifications 189 * specify non-type advancement options. 190 * 191 * Note this does not consider unit experience at all, it only checks option availability. 192 * See @ref advances if an experience check is necessary. 193 */ can_advance() const194 bool can_advance() const 195 { 196 return !advances_to_.empty() || !get_modification_advances().empty(); 197 } 198 199 /** 200 * Checks whether this unit is eligible for level-up. 201 * 202 * @retval true This unit has sufficient experience to level up and has advancement 203 * options available. 204 */ advances() const205 bool advances() const 206 { 207 return experience_ >= max_experience() && can_advance(); 208 } 209 210 /** 211 * Gets and image path and and associated description for each advancement option. 212 * 213 * Covers both type and modification-based advancements. 214 * 215 * @returns A data map, in image/description format. If the option is a unit type, 216 * advancement, the key is the type's image and the value the type ID. 217 * 218 * If the option is a modification, the key and value are set from config data 219 * (see @ref get_modification_advances). 220 */ 221 std::map<std::string, std::string> advancement_icons() const; 222 223 /** 224 * Gets any non-typed advanced options set by modifications. 225 * 226 * These are usually used to give a unit special advancement options that don't invole transforming to a 227 * new type. 228 * 229 * Note this is not the raw option data. Parsing is performed to ensure each option appears only once. 230 * Use @ref modification_advancements is the raw data is needed. 231 * 232 * @returns A config list of options data. Each option is unique. 233 */ 234 std::vector<config> get_modification_advances() const; 235 236 /** 237 * Gets the image and description data for modification advancements. 238 * 239 * @returns A list of pairs of the image paths(first) and descriptions (second) for 240 * each advancement option. 241 */ 242 std::vector<std::pair<std::string, std::string>> amla_icons() const; 243 244 using advancements_list= boost::ptr_vector<config>; 245 /** The raw, unparsed data for modification advancements. */ modification_advancements() const246 const advancements_list& modification_advancements() const 247 { 248 return advancements_; 249 } 250 251 /** Sets the raw modification advancement option data */ 252 void set_advancements(std::vector<config> advancements); 253 254 /** 255 * @} 256 * @defgroup unit_access Basic data setters and getters 257 * @{ 258 **/ 259 260 public: 261 /** 262 * The side this unit belongs to. 263 * 264 * Note that side numbers starts from 1, not 0, so be sure to subtract 1 if using as a container index. 265 */ side() const266 int side() const 267 { 268 return side_; 269 } 270 271 /** Sets the side this unit belongs to. */ set_side(unsigned int new_side)272 void set_side(unsigned int new_side) 273 { 274 side_ = new_side; 275 } 276 277 /** This unit's type, accounting for gender and variation. */ type() const278 const unit_type& type() const 279 { 280 return *type_; 281 } 282 283 /** 284 * The id of this unit's type. 285 * 286 * If you are dealing with creating units (e.g. recruitment), this is not what you want, as a 287 * variation can change this; use type().base_id() instead. 288 */ type_id() const289 const std::string& type_id() const 290 { 291 return type_->id(); 292 } 293 294 /** Gets the translatable name of this unit's type. */ type_name() const295 const t_string& type_name() const 296 { 297 return type_name_; 298 } 299 300 /** 301 * Gets this unit's id. 302 * 303 * This is a unique string usually set by WML. It should *not* be used for internal tracking in 304 * the unit_map. Use @ref underlying_id for that. 305 */ id() const306 const std::string& id() const 307 { 308 return id_; 309 } 310 311 /** Sets this unit's string ID. */ set_id(const std::string & id)312 void set_id(const std::string& id) 313 { 314 id_ = id; 315 } 316 317 /** This unit's unique internal ID. This should *not* be used for user-facing operations. */ underlying_id() const318 size_t underlying_id() const 319 { 320 return underlying_id_.value; 321 } 322 323 private: 324 /** Sets the internal ID. */ 325 void set_underlying_id(n_unit::id_manager& id_manager); 326 327 public: 328 /** Gets this unit's translatable display name. */ name() const329 const t_string& name() const 330 { 331 return name_; 332 } 333 334 /** 335 * Sets this unit's translatable display name. 336 * 337 * This should only be used internally since it ignores the 'unrenamable' flag. 338 */ set_name(const t_string & name)339 void set_name(const t_string& name) 340 { 341 name_ = name; 342 } 343 344 /** 345 * Attempts to rename this unit's translatable display name, taking the 'unrenamable' flag into account. 346 * 347 * If a direct rename is desired, use @ref set_name. 348 * @todo should this also take a t_string? 349 */ rename(const std::string & name)350 void rename(const std::string& name) 351 { 352 if(!unrenamable_) { 353 name_ = name; 354 } 355 } 356 357 /** 358 * Whether this unit can be renamed. 359 * 360 * This flag is considered by @ref rename, but not @ref set_name. 361 */ unrenamable() const362 bool unrenamable() const 363 { 364 return unrenamable_; 365 } 366 367 /** 368 * Sets the 'unrenamable' flag. Usually used for scenario-specific units which should not be renamed. 369 */ set_unrenamable(bool unrenamable)370 void set_unrenamable(bool unrenamable) 371 { 372 unrenamable_ = unrenamable; 373 } 374 375 /** A detailed description of this unit. */ unit_description() const376 t_string unit_description() const 377 { 378 return description_; 379 } 380 381 /** The gender of this unit. */ gender() const382 unit_race::GENDER gender() const 383 { 384 return gender_; 385 } 386 387 /** 388 * The alignment of this unit. 389 * 390 * This affects the time of day during which this unit's attacks do the most damage. 391 */ alignment() const392 unit_type::ALIGNMENT alignment() const 393 { 394 return alignment_; 395 } 396 397 /** Sets the alignment of this unit. */ set_alignment(unit_type::ALIGNMENT alignment)398 void set_alignment(unit_type::ALIGNMENT alignment) 399 { 400 alignment_ = alignment; 401 } 402 403 /** 404 * Gets this unit's race. 405 * 406 * @returns A pointer to a unit_race object - never nullptr, but it may point 407 * to the null race. 408 */ race() const409 const unit_race* race() const 410 { 411 return race_; 412 } 413 414 /** The current number of hitpoints this unit has. */ hitpoints() const415 int hitpoints() const 416 { 417 return hit_points_; 418 } 419 420 /** The max number of hitpoints this unit can have. */ max_hitpoints() const421 int max_hitpoints() const 422 { 423 return max_hit_points_; 424 } 425 426 /** Sets the current hitpoint amount. */ set_hitpoints(int hp)427 void set_hitpoints(int hp) 428 { 429 hit_points_ = hp; 430 } 431 432 /** The current number of experience points this unit has. */ experience() const433 int experience() const 434 { 435 return experience_; 436 } 437 438 /** The max number of experience points this unit can have. */ max_experience() const439 int max_experience() const 440 { 441 return max_experience_; 442 } 443 444 /** The number of experience points this unit needs to level up, or 0 if current XP > max XP. */ experience_to_advance() const445 unsigned int experience_to_advance() const 446 { 447 return std::max(0, max_experience_ - experience_); 448 } 449 450 /** The number of experience points over max this unit has, or 0 if current XP < max XP. */ experience_overflow() const451 unsigned int experience_overflow() const 452 { 453 return std::max(0, experience_ - max_experience_); 454 } 455 456 /** Sets the current experience point amount. */ set_experience(int xp)457 void set_experience(int xp) 458 { 459 experience_ = xp; 460 } 461 462 /** The current level of this unit. */ level() const463 int level() const 464 { 465 return level_; 466 } 467 468 /** Sets the current level of this unit. */ set_level(int level)469 void set_level(int level) 470 { 471 level_ = level; 472 } 473 474 /** The ID of the variation of this unit's type. */ variation() const475 const std::string& variation() const 476 { 477 return variation_; 478 } 479 480 /** The ID of the undead variation (ie, dwarf, swimmer) of this unit. */ undead_variation() const481 const std::string& undead_variation() const 482 { 483 return undead_variation_; 484 } 485 486 /** 487 * An optional profile image to display in Help. 488 * 489 * @returns The specified image, this unit's type's sprite image if empty 490 * or 'unit_image' was set. 491 */ 492 std::string small_profile() const; 493 494 /** 495 * An optional profile image displays when this unit is 'speaking' via [message]. 496 * 497 * @returns The specified image, this unit's type's sprite image if empty 498 * or 'unit_image' was set. 499 */ 500 std::string big_profile() const; 501 502 /** Whether this unit can recruit other units - ie, are they a leader unit. */ can_recruit() const503 bool can_recruit() const 504 { 505 return canrecruit_; 506 } 507 508 /** Sets whether this unit can recruit other units. */ set_can_recruit(bool canrecruit)509 void set_can_recruit(bool canrecruit) 510 { 511 canrecruit_ = canrecruit; 512 } 513 514 /** The type IDs of the other units this unit may recruit, if possible. */ recruits() const515 const std::vector<std::string>& recruits() const 516 { 517 return recruit_list_; 518 } 519 520 /** Sets the recruit list. */ 521 void set_recruits(const std::vector<std::string>& recruits); 522 523 /** How much gold is required to recruit this unit. */ cost() const524 int cost() const 525 { 526 return unit_value_; 527 } 528 529 /** How much gold it costs to recall this unit, or -1 if the side's default 530 * recall cost is used. */ recall_cost() const531 int recall_cost() const 532 { 533 return recall_cost_; 534 } 535 536 /** Sets the cost of recalling this unit. */ set_recall_cost(int recall_cost)537 void set_recall_cost(int recall_cost) 538 { 539 recall_cost_ = recall_cost; 540 } 541 542 /** Gets the filter constraints upon which units this unit may recall, if able. */ recall_filter() const543 const config& recall_filter() const 544 { 545 return filter_recall_; 546 } 547 548 /** 549 * Gets this unit's role. 550 * 551 * A role is a special string flag usually used to represent a unit's purpose in a scenario. 552 * It can be filtered on. 553 */ get_role() const554 const std::string& get_role() const 555 { 556 return role_; 557 } 558 559 /** Sets a unit's role */ set_role(const std::string & role)560 void set_role(const std::string& role) 561 { 562 role_ = role; 563 } 564 565 /** 566 * Gets this unit's usage. This is relevant to the AI. 567 * 568 * Usage refers to how the AI may consider utilizing this unit in combat. 569 * @todo document further 570 */ usage() const571 std::string usage() const 572 { 573 return unit_detail::get_or_default(usage_); 574 } 575 576 /** Sets this unit's usage. */ set_usage(const std::string & usage)577 void set_usage(const std::string& usage) 578 { 579 usage_.reset(new std::string(usage)); 580 } 581 582 /** 583 * Gets any user-defined variables this unit 'owns'. 584 * 585 * These are accessible via WML if the unit's data is serialized to a variable. They're strictly 586 * user-facing; internal engine calculations shouldn't use this. 587 */ variables()588 config& variables() 589 { 590 return variables_; 591 } 592 593 /** Const overload of @ref variables. */ variables() const594 const config& variables() const 595 { 596 return variables_; 597 } 598 599 /** 600 * Gets whether this unit is currently hidden on the map. 601 * @todo document hiddenness 602 */ get_hidden() const603 bool get_hidden() const 604 { 605 return hidden_; 606 } 607 608 /** Sets whether the unit is hidden on the map. */ 609 void set_hidden(bool state) const; 610 611 /** 612 * The factor by which the HP bar should be scaled. 613 * @todo: document further 614 */ hp_bar_scaling() const615 double hp_bar_scaling() const 616 { 617 return hp_bar_scaling_; 618 } 619 620 /** 621 * The factor by which the XP bar should be scaled. 622 * @todo: document further 623 */ xp_bar_scaling() const624 double xp_bar_scaling() const 625 { 626 return xp_bar_scaling_; 627 } 628 629 /** 630 * Whether the unit has been instructed to hold its position. 631 * This excludes it from the unit cycling function. 632 * @return true if it is holding position 633 */ hold_position() const634 bool hold_position() const 635 { 636 return hold_position_; 637 } 638 639 /** 640 * Toggle the unit's hold position status. 641 */ toggle_hold_position()642 void toggle_hold_position() 643 { 644 hold_position_ = !hold_position_; 645 if(hold_position_) { 646 end_turn_ = true; 647 } 648 } 649 650 /** 651 * Set whether the user ended their turn 652 * @todo Verify meaning and explain better 653 */ set_user_end_turn(bool value=true)654 void set_user_end_turn(bool value = true) 655 { 656 end_turn_ = value; 657 } 658 659 /** 660 * Toggle whether the user ended their turn 661 * @todo Verify meaning and explain better 662 */ toggle_user_end_turn()663 void toggle_user_end_turn() 664 { 665 end_turn_ = !end_turn_; 666 if(!end_turn_) { 667 hold_position_ = false; 668 } 669 } 670 671 /** 672 * Check whether the user ended their turn 673 * @todo Verify meaning and explain better 674 */ user_end_turn() const675 bool user_end_turn() const 676 { 677 return end_turn_; 678 } 679 680 /** 681 * Refresh unit for the beginning of a turn 682 */ 683 void new_turn(); 684 685 /** 686 * Refresh unit for the end of a turn 687 */ 688 void end_turn(); 689 690 /** 691 * Refresh unit for the beginning of a new scenario 692 */ 693 void new_scenario(); 694 695 /** 696 * Damage the unit. 697 * @returns true if the unit dies as a result 698 */ take_hit(int damage)699 bool take_hit(int damage) 700 { 701 hit_points_ -= damage; 702 return hit_points_ <= 0; 703 } 704 705 /** 706 * Heal the unit 707 * @amount The number of hitpoints to gain 708 */ 709 void heal(int amount); 710 711 /** 712 * Fully heal the unit, restoring it to max hitpoints 713 */ heal_fully()714 void heal_fully() 715 { 716 hit_points_ = max_hitpoints(); 717 } 718 719 /** 720 * Get the status effects currently affecting the unit. 721 * @return A set of status keys 722 */ 723 const std::set<std::string> get_states() const; 724 725 /** 726 * Check if the unit is affected by a status effect 727 * @param state The status effect to check 728 * @returns true if the unit is affected by the status effect 729 */ 730 bool get_state(const std::string& state) const; 731 732 /** 733 * Set whether the unit is affected by a status effect 734 * @param state The status effect to change 735 * @param value Whether the unit should be affected by the status 736 */ 737 void set_state(const std::string& state, bool value); 738 739 /** 740 * Built-in status effects known to the engine 741 */ 742 enum state_t { 743 STATE_SLOWED = 0, ///< The unit is slowed - it moves slower and does less damage 744 STATE_POISONED, ///< The unit is poisoned - it loses health each turn 745 STATE_PETRIFIED, ///< The unit is petrified - it cannot move or be attacked 746 STATE_UNCOVERED, ///< The unit is uncovered - it was hiding but has been spotted 747 STATE_NOT_MOVED, ///< The unit has not moved @todo Explain better 748 STATE_UNHEALABLE, ///< The unit cannot be healed 749 STATE_GUARDIAN, ///< The unit is a guardian - it won't move unless a target is sighted 750 STATE_UNKNOWN = -1///< A status effect not known to the engine 751 }; 752 753 /** 754 * Set whether the unit is affected by a status effect 755 * @param state The status effect to change 756 * @param value Whether the unit should be affected by the status 757 */ 758 void set_state(state_t state, bool value); 759 760 /** 761 * Check if the unit is affected by a status effect 762 * @param state The status effect to check 763 * @returns true if the unit is affected by the status effect 764 */ 765 bool get_state(state_t state) const; 766 767 /** 768 * Convert a string status effect ID to a built-in status effect ID 769 * @returns the state_t representing the status, or STATE_UNKNOWN if it's not built-in 770 */ 771 static state_t get_known_boolean_state_id(const std::string& state); 772 773 /** 774 * Check if the unit has been poisoned 775 * @returns true if it's poisoned 776 */ poisoned() const777 bool poisoned() const 778 { 779 return get_state(STATE_POISONED); 780 } 781 782 /** 783 * Check if the unit has been petrified 784 * @returns true if it's petrified 785 */ incapacitated() const786 bool incapacitated() const 787 { 788 return get_state(STATE_PETRIFIED); 789 } 790 791 /** 792 * Check if the unit has been slowed 793 * @returns true if it's slowed 794 */ slowed() const795 bool slowed() const 796 { 797 return get_state(STATE_SLOWED); 798 } 799 800 /** 801 * @} 802 * @defgroup unit_atk Attack and resistance functions 803 * @{ 804 */ 805 806 public: 807 /** Gets an iterator over this unit's attacks. */ attacks()808 attack_itors attacks() 809 { 810 return make_attack_itors(attacks_); 811 } 812 813 /** Const overload of @ref attacks. */ attacks() const814 const_attack_itors attacks() const 815 { 816 return make_attack_itors(attacks_); 817 } 818 819 /** 820 * Adds a new attack to the unit. 821 * @param position An iterator pointing to the attack before which to insert the new one. 822 * @param args The arguments for constructing the attack 823 */ 824 template<typename... Args> add_attack(attack_itors::iterator position,Args &&...args)825 attack_ptr add_attack(attack_itors::iterator position, Args&&... args) 826 { 827 return *attacks_.emplace(position.base(), new attack_type(std::forward<Args>(args)...)); 828 } 829 830 /** 831 * Remove an attack from the unit 832 * @param atk A pointer to the attack to remove 833 * @return true if the attack was removed, false if it didn't exist on the unit 834 */ 835 bool remove_attack(attack_ptr atk); 836 837 /** 838 * Set the unit to have no attacks left for this turn. 839 */ 840 void remove_attacks_ai(); 841 842 /** 843 * Calculates the damage this unit would take from a certain attack. 844 * 845 * @param attack The attack to consider. 846 * @param attacker Whether this unit should be considered the attacker. 847 * @param loc TODO: what does this do? 848 * 849 * @returns The expected damage. 850 */ damage_from(const attack_type & attack,bool attacker,const map_location & loc) const851 int damage_from(const attack_type& attack, bool attacker, const map_location& loc) const 852 { 853 return resistance_against(attack, attacker, loc); 854 } 855 856 /** The maximum number of attacks this unit may perform per turn, usually 1. */ max_attacks() const857 int max_attacks() const 858 { 859 return max_attacks_; 860 } 861 862 /** 863 * Gets the remaining number of attacks this unit can perform this turn. 864 * 865 * If the 'incapacitated' status is set, this will always be 0. 866 */ attacks_left() const867 int attacks_left() const 868 { 869 return (attacks_left_ == 0 || incapacitated()) ? 0 : attacks_left_; 870 } 871 872 /** 873 * Gets the remaining number of attacks this unit can perform this turn. 874 * 875 * @param base_value If false, consider the `incapacitated` flag. 876 * 877 * @returns If @a base_value is true, the raw value is returned. 878 */ attacks_left(bool base_value) const879 int attacks_left(bool base_value) const 880 { 881 return base_value ? attacks_left_ : attacks_left(); 882 } 883 884 /** 885 * Sets the number of attacks this unit has left this turn. 886 * @param left The number of attacks left 887 */ set_attacks(int left)888 void set_attacks(int left) 889 { 890 attacks_left_ = std::max<int>(0, left); 891 } 892 893 /** 894 * The unit's defense on a given terrain 895 * @param terrain The terrain to check 896 */ 897 int defense_modifier(const t_translation::terrain_code& terrain) const; 898 899 /** 900 * The unit's resistance against a given damage type 901 * @param damage_name The damage type 902 * @param attacker True if this unit is on the offensive (to resolve [resistance] abilities) 903 * @param loc The unit's location (to resolve [resistance] abilities) 904 */ 905 int resistance_against(const std::string& damage_name, bool attacker, const map_location& loc) const; 906 907 /** 908 * The unit's resistance against a given attack 909 * @param atk The attack 910 * @param attacker True if this unit is on the offensive (to resolve [resistance] abilities) 911 * @param loc The unit's location (to resolve [resistance] abilities) 912 */ resistance_against(const attack_type & atk,bool attacker,const map_location & loc) const913 int resistance_against(const attack_type& atk, bool attacker, const map_location& loc) const 914 { 915 return resistance_against(atk.type(), attacker, loc); 916 } 917 918 /** Gets resistances without any abilities applied. */ get_base_resistances() const919 utils::string_map get_base_resistances() const 920 { 921 return movement_type_.damage_table(); 922 } 923 924 private: 925 bool resistance_filter_matches(const config& cfg, bool attacker, const std::string& damage_name, int res) const; 926 927 /** 928 * @} 929 * @defgroup unit_trait Trait and upkeep functions 930 * @{ 931 */ 932 public: 933 /** 934 * Applies mandatory traits (e.g. undead, mechanical) to a unit and then fills in the remaining traits 935 * traits until no more are available (leaders have a restricted set of available traits) or the unit has 936 * its maximum number of traits. 937 * 938 * This routine does not apply the effects of added traits to a unit; that must be done by the caller. 939 * 940 * Note that random numbers used in config files don't work in multiplayer, so leaders should be barred 941 * from all random traits until that is fixed. Later the restrictions will be based on play balance. 942 * 943 * @param must_have_only Whether random or optional traits should be included or not. If false only 944 * mandatory traits will be used. 945 */ 946 void generate_traits(bool must_have_only = false); 947 948 /** 949 * Gets the names of the currently registered traits. 950 * 951 * @returns A list of translatable trait names. 952 */ trait_names() const953 const std::vector<t_string>& trait_names() const 954 { 955 return trait_names_; 956 } 957 958 /** 959 * Gets the descriptions of the currently registered traits. 960 * 961 * @returns A list of translatable trait descriptions. 962 */ trait_descriptions() const963 const std::vector<t_string>& trait_descriptions() const 964 { 965 return trait_descriptions_; 966 } 967 968 /** 969 * Gets a list of the traits this unit currently has. 970 * 971 * @returns A list of trait IDs. 972 */ 973 std::vector<std::string> get_traits_list() const; 974 975 /** 976 * Register a trait's name and its description for the UI's use. 977 * 978 * The resulting data can be fetched with @ref trait_names and @ref trait_descriptions. 979 * 980 * @param trait A config containing the trait's attributes. 981 * @param description The translatable description of the trait. 982 */ 983 void add_trait_description(const config& trait, const t_string& description); 984 985 /** 986 * Gets the amount of gold this unit costs a side per turn. 987 * 988 * This fetches an actual numeric gold value: 989 * - If @rec can_recruit is true, no upkeep is paid (0 is returned). 990 * - If a special upkeep flag is set, the associated gold amount is returned (see @ref upkeep_value_visitor). 991 * - If a numeric value is already set, it is returned directly. 992 * 993 * @returns A gold value, evaluated based on the state of @ref upkeep_raw. 994 */ 995 int upkeep() const; 996 997 struct upkeep_full 998 { typeunit::upkeep_full999 static std::string type() { static std::string v = "full"; return v; } 1000 }; 1001 1002 struct upkeep_loyal 1003 { typeunit::upkeep_loyal1004 static std::string type() { static std::string v = "loyal"; return v; } 1005 }; 1006 1007 /** Visitor helper class to fetch the appropriate upkeep value. */ 1008 class upkeep_value_visitor : public boost::static_visitor<int> 1009 { 1010 public: upkeep_value_visitor(const unit & unit)1011 explicit upkeep_value_visitor(const unit& unit) : u_(unit) {} 1012 1013 /** Full upkeep equals the unit's level. */ operator ()(const upkeep_full &) const1014 int operator()(const upkeep_full&) const 1015 { 1016 return u_.level(); 1017 } 1018 1019 /** Loyal units cost no upkeep. */ operator ()(const upkeep_loyal &) const1020 int operator()(const upkeep_loyal&) const 1021 { 1022 return 0; 1023 } 1024 operator ()(int v) const1025 int operator()(int v) const 1026 { 1027 return v; 1028 } 1029 1030 private: 1031 const unit& u_; 1032 }; 1033 1034 /** Visitor helper struct to fetch the upkeep type flag if applicable, or the the value otherwise. */ 1035 struct upkeep_type_visitor : public boost::static_visitor<std::string> 1036 { 1037 template<typename T> 1038 utils::enable_if_t<!std::is_same<int, T>::value, std::string> operator ()unit::upkeep_type_visitor1039 operator()(T&) const 1040 { 1041 // Any special upkeep type should have an associated @ref type getter in its helper struct. 1042 return T::type(); 1043 } 1044 operator ()unit::upkeep_type_visitor1045 std::string operator()(int v) const 1046 { 1047 return std::to_string(v); 1048 } 1049 }; 1050 1051 using upkeep_t = boost::variant<upkeep_full, upkeep_loyal, int>; 1052 1053 /** 1054 * Gets the raw variant controlling the upkeep value. 1055 * 1056 * This should not usually be called directly. To get an actual numeric value of upkeep use @ref upkeep. 1057 */ upkeep_raw() const1058 upkeep_t upkeep_raw() const 1059 { 1060 return upkeep_; 1061 } 1062 1063 /** Sets the upkeep value to a specific value value. Does not necessarily need to be numeric */ set_upkeep(upkeep_t v)1064 void set_upkeep(upkeep_t v) 1065 { 1066 upkeep_ = v; 1067 } 1068 1069 /** Gets whether this unit is loyal - ie, it costs no upkeep. */ 1070 bool loyal() const; 1071 1072 /** Gets whether this unit is fearless - ie, unaffected by time of day. */ is_fearless() const1073 bool is_fearless() const 1074 { 1075 return is_fearless_; 1076 } 1077 1078 /** Gets whether this unit is healthy - ie, always rest heals. */ is_healthy() const1079 bool is_healthy() const 1080 { 1081 return is_healthy_; 1082 } 1083 1084 /** 1085 * @} 1086 * @defgroup unit_mvmt Movement and location functions 1087 * @{ 1088 */ 1089 1090 public: 1091 /** The maximum moves this unit has. */ total_movement() const1092 int total_movement() const 1093 { 1094 return max_movement_; 1095 } 1096 1097 /** 1098 * Gets how far a unit can move, considering the `incapacitated` flag. 1099 * 1100 * @returns The remaining movement, or zero if incapacitated. 1101 */ movement_left() const1102 int movement_left() const 1103 { 1104 return (movement_ == 0 || incapacitated()) ? 0 : movement_; 1105 } 1106 1107 /** 1108 * Gets how far a unit can move. 1109 * 1110 * @param base_value If false, consider the `incapacitated` flag. 1111 * 1112 * @returns If @a base_value is true, the raw value is returned. 1113 */ movement_left(bool base_value) const1114 int movement_left(bool base_value) const 1115 { 1116 return base_value ? movement_ : movement_left(); 1117 } 1118 1119 /** 1120 * Set this unit's remaining movement to @a moves. 1121 * 1122 * This does not affect maximum movement. 1123 * 1124 * @param moves The new number of moves 1125 * @param unit_action If to true, the "end turn" and "hold position" flags will be cleared 1126 * (as they should be if a unit acts, as opposed to the movement being set 1127 * by the engine for other reasons). 1128 */ 1129 void set_movement(int moves, bool unit_action = false); 1130 1131 /** Checks if this unit has moved. */ has_moved() const1132 bool has_moved() const 1133 { 1134 return movement_left() != total_movement(); 1135 } 1136 1137 /** Sets the unit to have no moves left for this turn. */ 1138 void remove_movement_ai(); 1139 1140 /** 1141 * Checks whether this unit is 'resting'. 1142 * 1143 * Resting refers to whether this unit has not moved yet this turn. Note that this can be true even 1144 * if @ref movement_left is not equal to @ref total_movement. 1145 */ resting() const1146 bool resting() const 1147 { 1148 return resting_; 1149 } 1150 1151 /** Sets this unit's resting status. */ set_resting(bool rest)1152 void set_resting(bool rest) 1153 { 1154 resting_ = rest; 1155 } 1156 1157 /** Tests whether the unit has a zone-of-control, considering @ref incapacitated. */ emits_zoc() const1158 bool emits_zoc() const 1159 { 1160 return emit_zoc_ && !incapacitated(); 1161 } 1162 1163 /** Gets the raw zone-of-control flag, disregarding @ref incapacitated. */ get_emit_zoc() const1164 bool get_emit_zoc() const 1165 { 1166 return emit_zoc_; 1167 } 1168 1169 /** Sets the raw zone-of-control flag. */ set_emit_zoc(bool val)1170 void set_emit_zoc(bool val) 1171 { 1172 emit_zoc_ = val; 1173 } 1174 1175 /** The current map location this unit is at. */ get_location() const1176 const map_location& get_location() const 1177 { 1178 return loc_; 1179 } 1180 1181 /** 1182 * Sets this unit's map location. 1183 * 1184 * Note this should only be called by unit_map or for temporary units. 1185 */ set_location(const map_location & loc)1186 void set_location(const map_location& loc) 1187 { 1188 loc_ = loc; 1189 } 1190 1191 /** The current directin this unit is facing within its hex. */ facing() const1192 map_location::DIRECTION facing() const 1193 { 1194 return facing_; 1195 } 1196 1197 /** The this unit's facing. */ 1198 void set_facing(map_location::DIRECTION dir) const; 1199 1200 /** Gets whether this unit has a multi-turn destination set. */ has_goto() const1201 bool has_goto() const 1202 { 1203 return get_goto().valid(); 1204 } 1205 1206 /** The map location to which this unit is moving over multiple turns, if any. */ get_goto() const1207 const map_location& get_goto() const 1208 { 1209 return goto_; 1210 } 1211 1212 /** Sets this unit's long term destination. */ set_goto(const map_location & new_goto)1213 void set_goto(const map_location& new_goto) 1214 { 1215 goto_ = new_goto; 1216 } 1217 1218 /** Gets the unit's vision points. */ vision() const1219 int vision() const 1220 { 1221 return vision_ < 0 ? max_movement_ : vision_; 1222 } 1223 1224 /** Gets the unit's jamming points. */ jamming() const1225 int jamming() const 1226 { 1227 return jamming_; 1228 } 1229 1230 /** Check whether the unit's move has been interrupted. */ move_interrupted() const1231 bool move_interrupted() const 1232 { 1233 return movement_left() > 0 && interrupted_move_.x >= 0 && interrupted_move_.y >= 0; 1234 } 1235 1236 /** Get the target location of the unit's interrupted move. */ get_interrupted_move() const1237 const map_location& get_interrupted_move() const 1238 { 1239 return interrupted_move_; 1240 } 1241 1242 /** Set the target location of the unit's interrupted move. */ set_interrupted_move(const map_location & interrupted_move)1243 void set_interrupted_move(const map_location& interrupted_move) 1244 { 1245 interrupted_move_ = interrupted_move; 1246 } 1247 1248 /** Get the unit's movement type. */ movement_type() const1249 const movetype& movement_type() const 1250 { 1251 return movement_type_; 1252 } 1253 1254 /** 1255 * Get the unit's movement cost on a particular terrain 1256 * @param terrain The terrain to check 1257 * @returns the number of movement points to enter that terrain 1258 */ movement_cost(const t_translation::terrain_code & terrain) const1259 int movement_cost(const t_translation::terrain_code& terrain) const 1260 { 1261 return movement_type_.movement_cost(terrain, get_state(STATE_SLOWED)); 1262 } 1263 1264 /** 1265 * Get the unit's vision cost on a particular terrain 1266 * @param terrain The terrain to check 1267 * @returns the number of vision points to see into that terrain 1268 */ vision_cost(const t_translation::terrain_code & terrain) const1269 int vision_cost(const t_translation::terrain_code& terrain) const 1270 { 1271 return movement_type_.vision_cost(terrain, get_state(STATE_SLOWED)); 1272 } 1273 1274 /** 1275 * Get the unit's jamming cost on a particular terrain 1276 * @param terrain The terrain to check 1277 * @returns the number of jamming points to jam that terrain 1278 */ jamming_cost(const t_translation::terrain_code & terrain) const1279 int jamming_cost(const t_translation::terrain_code& terrain) const 1280 { 1281 return movement_type_.jamming_cost(terrain, get_state(STATE_SLOWED)); 1282 } 1283 1284 /** Check if the unit is a flying unit. */ is_flying() const1285 bool is_flying() const 1286 { 1287 return movement_type_.is_flying(); 1288 } 1289 1290 /** 1291 * @} 1292 * @defgroup unit_mod Modification functions 1293 * @{ 1294 */ 1295 1296 public: 1297 /** Get the raw modifications. */ get_modifications()1298 config& get_modifications() 1299 { 1300 return modifications_; 1301 } 1302 1303 /** Set the raw modifications. */ get_modifications() const1304 const config& get_modifications() const 1305 { 1306 return modifications_; 1307 } 1308 1309 /** 1310 * Count modifications of a particular type. 1311 * @param type The type of modification to count. 1312 * Valid values are "advancement", "trait", "object" 1313 * @param id The ID of the modification to count 1314 * @return The total number of modifications of that type and ID. 1315 */ 1316 size_t modification_count(const std::string& type, const std::string& id) const; 1317 1318 /** 1319 * Add a new modification to the unit. 1320 * @param type The type of modification to add. 1321 * Valid values are "advancement", "trait", "object" 1322 * @param modification The details of the modification 1323 * @param no_add If true, apply the modification but don't save it for unit rebuild time. 1324 * Defaults to false. 1325 */ 1326 void add_modification(const std::string& type, const config& modification, bool no_add = false); 1327 1328 /** 1329 * Clears those modifications whose duration has expired. 1330 * 1331 * @param duration If empty, all temporary modifications (those not lasting forever) expire. 1332 * Otherwise, modifications whose duration equals @a duration expire. 1333 */ 1334 void expire_modifications(const std::string& duration); 1335 1336 static const std::set<std::string> builtin_effects; 1337 1338 /** 1339 * Apply a builtin effect to the unit. 1340 * @param type The effect to apply. Must be one of the effects in @ref builtin_effects. 1341 * @param effect The details of the effect 1342 */ 1343 void apply_builtin_effect(std::string type, const config& effect); 1344 1345 /** 1346 * Construct a string describing a built-in effect. 1347 * @param type The effect to describe. Must be one of the effects in @ref builtin_effects. 1348 * @param effect The details of the effect 1349 */ 1350 std::string describe_builtin_effect(std::string type, const config& effect); 1351 1352 /** Re-apply all saved modifications. */ 1353 void apply_modifications(); 1354 1355 /** 1356 * @} 1357 * @defgroup unit_img Image and animations functions 1358 * @{ 1359 */ 1360 1361 public: 1362 /** @todo Document this */ anim_comp() const1363 unit_animation_component& anim_comp() const 1364 { 1365 return *anim_comp_; 1366 } 1367 1368 /** The name of the file to game_display (used in menus). */ 1369 std::string absolute_image() const; 1370 1371 /** The default image to use for animation frames with no defined image. */ 1372 std::string default_anim_image() const; 1373 1374 /** Get the unit's halo image. */ image_halo() const1375 std::string image_halo() const 1376 { 1377 return unit_detail::get_or_default(halo_); 1378 } 1379 1380 /** Set the unit's halo image. */ 1381 void set_image_halo(const std::string& halo); 1382 1383 /** Get the unit's ellipse image. */ image_ellipse() const1384 std::string image_ellipse() const 1385 { 1386 return unit_detail::get_or_default(ellipse_); 1387 } 1388 1389 /** Set the unit's ellipse image. */ set_image_ellipse(const std::string & ellipse)1390 void set_image_ellipse(const std::string& ellipse) 1391 { 1392 appearance_changed_ = true; 1393 ellipse_.reset(new std::string(ellipse)); 1394 } 1395 1396 /** 1397 * Get the source color palette to use when recoloring the unit's image. 1398 */ 1399 const std::string& flag_rgb() const; 1400 1401 /** Constructs a recolor (RC) IPF string for this unit's team color. */ 1402 std::string TC_image_mods() const; 1403 1404 /** Gets any IPF image mods applied by effects. */ effect_image_mods() const1405 const std::string& effect_image_mods() const 1406 { 1407 return image_mods_; 1408 } 1409 1410 /** 1411 * Gets an IPF string containing all IPF image mods. 1412 * 1413 * @returns An amalgamation of @ref effect_image_mods followed by @ref TC_image_mods. 1414 */ 1415 std::string image_mods() const; 1416 1417 /** Get the unit's overlay images. */ overlays() const1418 const std::vector<std::string>& overlays() const 1419 { 1420 return overlays_; 1421 } 1422 1423 /** 1424 * Color for this unit's *current* hitpoints. 1425 * 1426 * @returns A color between green and red representing how wounded this unit is. 1427 * The maximum_hitpoints are considered as base. 1428 */ 1429 color_t hp_color() const; 1430 1431 /** 1432 * Color for this unit's hitpoints. 1433 * 1434 * @param hitpoints The number of hitpoints the color represents. 1435 * @returns The color considering the current hitpoints as base. 1436 */ 1437 color_t hp_color(int hitpoints) const; 1438 1439 /** 1440 * Color for this unit's XP. See also @ref hp_color 1441 */ 1442 color_t xp_color() const; 1443 1444 /** 1445 * @} 1446 * @defgroup unit_abil Ability functions 1447 * @{ 1448 */ 1449 1450 public: 1451 /** 1452 * Checks whether this unit currently possesses or is affected by a given ability. 1453 * 1454 * This means that the ability could be owned by this unit itself or by an adjacent unit, should 1455 * the ability affect an AoE in which this unit happens to be. 1456 * 1457 * @param tag_name The name of the ability to check for. 1458 * @param loc The location around which to check for affected units. This may or 1459 * may not be the location of this unit. 1460 * @param dc A display_context object, used in calculations. 1461 */ 1462 bool get_ability_bool(const std::string& tag_name, const map_location& loc, const display_context& dc) const; 1463 1464 /** 1465 * Checks whether this unit currently possesses or is affected by a given ability. 1466 * 1467 * This means that the ability could be owned by this unit itself or by an adjacent unit, should 1468 * the ability affect an AoE in which this unit happens to be. 1469 * 1470 * This overload uses the location of this unit for calculations. 1471 * 1472 * @param tag_name The name of the ability to check for. 1473 * @param dc A display_context object, used in calculations. 1474 */ get_ability_bool(const std::string & tag_name,const display_context & dc) const1475 bool get_ability_bool(const std::string& tag_name, const display_context& dc) const 1476 { 1477 return get_ability_bool(tag_name, loc_, dc); 1478 } 1479 1480 /** 1481 * Gets the unit's active abilities of a particular type if it were on a specified location. 1482 * @param tag_name The type of ability to check for 1483 * @param loc The location to use for resolving abilities 1484 * @return A list of active abilities, paired with the location they are active on 1485 */ 1486 unit_ability_list get_abilities(const std::string& tag_name, const map_location& loc) const; 1487 1488 /** 1489 * Gets the unit's active abilities of a particular type. 1490 * @param tag_name The type of ability to check for 1491 * @return A list of active abilities, paired with the location they are active on 1492 */ get_abilities(const std::string & tag_name) const1493 unit_ability_list get_abilities(const std::string& tag_name) const 1494 { 1495 return get_abilities(tag_name, loc_); 1496 } 1497 1498 /** 1499 * Gets the names and descriptions of this unit's abilities. Location-independent variant 1500 * with all abilities shown as active. 1501 * 1502 * @returns A list of quadruples consisting of (in order) id, base name, 1503 * male or female name as appropriate for the unit, and description. 1504 */ 1505 std::vector<std::tuple<std::string, t_string, t_string, t_string>> 1506 ability_tooltips() const; 1507 1508 /** 1509 * Gets the names and descriptions of this unit's abilities. 1510 * 1511 * @param active_list This vector will be the same length as the returned one and will 1512 * indicate whether or not the corresponding ability is active. 1513 * 1514 * @param loc The location on which to resolve the ability. 1515 * 1516 * @returns A list of quadruples consisting of (in order) id, base name, 1517 * male or female name as appropriate for the unit, and description. 1518 */ 1519 std::vector<std::tuple<std::string, t_string, t_string, t_string>> 1520 ability_tooltips(boost::dynamic_bitset<>& active_list, const map_location& loc) const; 1521 1522 /** Get a list of all abilities by ID. */ 1523 std::vector<std::string> get_ability_list() const; 1524 1525 /** 1526 * Check if the unit has an ability of a specific type. 1527 * @param ability The type of ability (tag name) to check for. 1528 * @returns true if the ability is present 1529 */ 1530 bool has_ability_type(const std::string& ability) const; 1531 1532 /** 1533 * Check if the unit has an ability of a specific ID. 1534 * @param ability The ID of ability to check for. 1535 * @returns true if the ability is present 1536 */ 1537 bool has_ability_by_id(const std::string& ability) const; 1538 1539 /** 1540 * Removes a unit's abilities with a specific ID. 1541 * @param ability The type of ability (tag name) to remove. 1542 */ 1543 void remove_ability_by_id(const std::string& ability); 1544 1545 private: 1546 /** 1547 * Check if an ability is active. 1548 * @param ability The type (tag name) of the ability 1549 * @param cfg an ability WML structure 1550 * @param loc The location on which to resolve the ability 1551 * @returns true if it is active 1552 */ 1553 bool ability_active(const std::string& ability, const config& cfg, const map_location& loc) const; 1554 1555 /** 1556 * Check if an ability affects adjacent units. 1557 * @param ability The type (tag name) of the ability 1558 * @param cfg an ability WML structure 1559 * @param loc The location on which to resolve the ability 1560 * @param from The "other unit" for filter matching 1561 */ 1562 bool ability_affects_adjacent(const std::string& ability, const config& cfg, int dir, const map_location& loc, const unit& from) const; 1563 1564 /** 1565 * Check if an ability affects the owning unit. 1566 * @param ability The type (tag name) of the ability 1567 * @param cfg an ability WML structure 1568 * @param loc The location on which to resolve the ability 1569 */ 1570 bool ability_affects_self(const std::string& ability, const config& cfg, const map_location& loc) const; 1571 1572 public: 1573 /** Get the unit formula manager. */ formula_manager() const1574 unit_formula_manager& formula_manager() const 1575 { 1576 return *formula_man_; 1577 } 1578 1579 /** Generates a random race-appropriate name if one has not already been provided. */ 1580 void generate_name(); 1581 1582 // Only see_all = true use caching 1583 bool invisible(const map_location& loc, const display_context& dc, bool see_all = true) const; 1584 1585 bool is_visible_to_team(const team& team, const display_context& dc, bool const see_all = true) const; 1586 /// Return true if the unit would be visible to team if its location were loc. 1587 bool is_visible_to_team(const map_location& loc, const team& team, const display_context& dc, bool const see_all = true) const; 1588 1589 /** 1590 * Serializes the current unit metadata values. 1591 * 1592 * @param cfg The config to write to. 1593 */ 1594 void write(config& cfg) const; 1595 1596 /** 1597 * Mark this unit as clone so it can be inserted to unit_map. 1598 * 1599 * @returns self (for convenience) 1600 */ 1601 unit& mark_clone(bool is_temporary); 1602 1603 /** @} */ 1604 ref_count() const1605 long ref_count() const 1606 { 1607 return ref_count_; 1608 } 1609 1610 friend void intrusive_ptr_add_ref(const unit*); 1611 friend void intrusive_ptr_release(const unit*); 1612 set_appearance_changed(bool value)1613 void set_appearance_changed(bool value) { appearance_changed_ = value; } appearance_changed() const1614 bool appearance_changed() const { return appearance_changed_; } 1615 1616 protected: 1617 mutable long ref_count_; // used by intrusive_ptr 1618 1619 private: 1620 map_location loc_; 1621 1622 std::vector<std::string> advances_to_; 1623 1624 /** Never nullptr. Adjusted for gender and variation. */ 1625 const unit_type* type_; 1626 1627 /** The displayed name of this unit type. */ 1628 t_string type_name_; 1629 1630 /** Never nullptr, but may point to the null race. */ 1631 const unit_race* race_; 1632 1633 std::string id_; 1634 t_string name_; 1635 n_unit::unit_id underlying_id_; 1636 1637 std::string undead_variation_; 1638 std::string variation_; 1639 1640 int hit_points_; 1641 int max_hit_points_; 1642 int experience_; 1643 int max_experience_; 1644 1645 int level_; 1646 1647 int recall_cost_; 1648 bool canrecruit_; 1649 std::vector<std::string> recruit_list_; 1650 unit_type::ALIGNMENT alignment_; 1651 1652 std::string flag_rgb_; 1653 std::string image_mods_; 1654 1655 bool unrenamable_; 1656 1657 int side_; 1658 1659 unit_race::GENDER gender_; 1660 1661 std::unique_ptr<unit_formula_manager> formula_man_; 1662 1663 int movement_; 1664 int max_movement_; 1665 int vision_; 1666 int jamming_; 1667 1668 movetype movement_type_; 1669 1670 bool hold_position_; 1671 bool end_turn_; 1672 bool resting_; 1673 1674 int attacks_left_; 1675 int max_attacks_; 1676 1677 std::set<std::string> states_; 1678 1679 static const size_t num_bool_states = 7; 1680 1681 std::bitset<num_bool_states> known_boolean_states_; 1682 static std::map<std::string, state_t> known_boolean_state_names_; 1683 1684 config variables_; 1685 config events_; 1686 config filter_recall_; 1687 1688 bool emit_zoc_; 1689 1690 std::vector<std::string> overlays_; 1691 1692 std::string role_; 1693 attack_list attacks_; 1694 1695 protected: 1696 // TODO: I think we actually consider this to be part of the gamestate, so it might be better if it's not mutable, 1697 // but it's not easy to separate this guy from the animation code right now. 1698 mutable map_location::DIRECTION facing_; 1699 1700 private: 1701 std::vector<t_string> trait_names_; 1702 std::vector<t_string> trait_descriptions_; 1703 1704 int unit_value_; 1705 map_location goto_, interrupted_move_; 1706 1707 bool is_fearless_, is_healthy_; 1708 1709 utils::string_map modification_descriptions_; 1710 1711 // Animations: 1712 friend class unit_animation_component; 1713 1714 std::unique_ptr<unit_animation_component> anim_comp_; 1715 1716 mutable bool hidden_; 1717 double hp_bar_scaling_, xp_bar_scaling_; 1718 1719 config modifications_; 1720 config abilities_; 1721 1722 advancements_list advancements_; 1723 1724 t_string description_; 1725 1726 std::unique_ptr<std::string> usage_; 1727 std::unique_ptr<std::string> halo_; 1728 std::unique_ptr<std::string> ellipse_; 1729 1730 bool random_traits_; 1731 bool generate_name_; 1732 1733 upkeep_t upkeep_; 1734 1735 std::string profile_; 1736 std::string small_profile_; 1737 1738 //Used to check whether the moving units during a move needs to be updated 1739 mutable bool appearance_changed_ = true; 1740 1741 void parse_upkeep(const config::attribute_value& upkeep); 1742 void write_upkeep(config::attribute_value& upkeep) const; 1743 1744 /** 1745 * Hold the visibility status cache for a unit, when not uncovered. 1746 * This is mutable since it is a cache. 1747 */ 1748 mutable std::map<map_location, bool> invisibility_cache_; 1749 1750 /** 1751 * Clears the cache. 1752 * 1753 * Since we don't change the state of the object we're marked const (also 1754 * required since the objects in the cache need to be marked const). 1755 */ clear_visibility_cache() const1756 void clear_visibility_cache() const 1757 { 1758 invisibility_cache_.clear(); 1759 } 1760 }; 1761 1762 /** Implement non-member swap function for std::swap (calls @ref unit::swap). */ 1763 void swap(unit& lhs, unit& rhs); 1764 1765 /** 1766 * Object which temporarily resets a unit's movement. 1767 * 1768 * @warning A unit whose movement is reset may not be deleted while held in a 1769 * @ref unit_movement_resetter object, so it's best to use thus only in a small scope. 1770 */ 1771 struct unit_movement_resetter 1772 { 1773 unit_movement_resetter(const unit_movement_resetter&) = delete; 1774 unit_movement_resetter& operator=(const unit_movement_resetter&) = delete; 1775 1776 unit_movement_resetter(const unit& u, bool operate = true); 1777 ~unit_movement_resetter(); 1778 1779 private: 1780 unit& u_; 1781 int moves_; 1782 }; 1783 1784 /** 1785 * Gets a checksum for a unit. 1786 * 1787 * In MP games the descriptions are locally generated and might differ, so it 1788 * should be possible to discard them. Not sure whether replays suffer the 1789 * same problem. 1790 * 1791 * @param u this unit 1792 * 1793 * @returns the checksum for a unit 1794 */ 1795 std::string get_checksum(const unit& u); 1796