64 #include <string_view>
69 #define DBG_UT LOG_STREAM(debug, log_unit)
70 #define LOG_UT LOG_STREAM(info, log_unit)
71 #define WRN_UT LOG_STREAM(warn, log_unit)
72 #define ERR_UT LOG_STREAM(err, log_unit)
77 const std::set<std::string_view> ModificationTypes {
"advancement",
"advance",
"trait",
"object" };
84 static std::vector<const unit*> units_with_cache;
86 static const std::string leader_crown_path =
"misc/leader-crown.png";
87 static const std::set<std::string_view> internalized_attrs {
158 auto cur_known = internalized_attrs.begin();
159 auto end_known = internalized_attrs.end();
161 while(cur_known != end_known) {
165 int comp = cur->first.compare(*cur_known);
167 WRN_UT <<
"Unknown attribute '" << cur->first <<
"' discarded.";
180 WRN_UT <<
"Unknown attribute '" << cur->first <<
"' discarded.";
192 if(type_id.empty()) {
195 std::string new_id = type_id;
204 const std::vector<unit_race::GENDER>& genders =
type.genders();
205 assert(genders.size() > 0);
207 if(random_gender ==
false || genders.size() == 1) {
208 return genders.front();
216 const std::string& gender = cfg[
"gender"];
217 if(!gender.empty()) {
226 : std::enable_shared_from_this<
unit>()
228 , advances_to_(o.advances_to_)
230 , type_name_(o.type_name_)
234 , underlying_id_(o.underlying_id_)
235 , undead_variation_(o.undead_variation_)
236 , variation_(o.variation_)
237 , hit_points_(o.hit_points_)
238 , max_hit_points_(o.max_hit_points_)
239 , experience_(o.experience_)
240 , max_experience_(o.max_experience_)
242 , recall_cost_(o.recall_cost_)
243 , canrecruit_(o.canrecruit_)
244 , recruit_list_(o.recruit_list_)
245 , alignment_(o.alignment_)
246 , flag_rgb_(o.flag_rgb_)
247 , image_mods_(o.image_mods_)
248 , unrenamable_(o.unrenamable_)
252 , movement_(o.movement_)
253 , max_movement_(o.max_movement_)
255 , jamming_(o.jamming_)
256 , movement_type_(o.movement_type_)
257 , hold_position_(o.hold_position_)
258 , end_turn_(o.end_turn_)
259 , resting_(o.resting_)
260 , attacks_left_(o.attacks_left_)
261 , max_attacks_(o.max_attacks_)
263 , known_boolean_states_(o.known_boolean_states_)
264 , variables_(o.variables_)
266 , filter_recall_(o.filter_recall_)
267 , emit_zoc_(o.emit_zoc_)
268 , overlays_(o.overlays_)
270 , attacks_(o.attacks_)
272 , trait_names_(o.trait_names_)
273 , trait_descriptions_(o.trait_descriptions_)
274 , unit_value_(o.unit_value_)
276 , interrupted_move_(o.interrupted_move_)
277 , is_fearless_(o.is_fearless_)
278 , is_healthy_(o.is_healthy_)
279 , modification_descriptions_(o.modification_descriptions_)
282 , hp_bar_scaling_(o.hp_bar_scaling_)
283 , xp_bar_scaling_(o.xp_bar_scaling_)
284 , modifications_(o.modifications_)
285 , abilities_(o.abilities_)
286 , advancements_(o.advancements_)
287 , description_(o.description_)
288 , special_notes_(o.special_notes_)
291 , ellipse_(o.ellipse_)
292 , random_traits_(o.random_traits_)
293 , generate_name_(o.generate_name_)
295 , profile_(o.profile_)
296 , small_profile_(o.small_profile_)
297 , changed_attributes_(o.changed_attributes_)
298 , invisibility_cache_()
307 : std::enable_shared_from_this<
unit>()
316 , undead_variation_()
329 , unrenamable_(false)
338 , hold_position_(false)
344 , known_boolean_states_()
354 , trait_descriptions_()
357 , interrupted_move_()
358 , is_fearless_(false)
360 , modification_descriptions_()
373 , random_traits_(true)
374 , generate_name_(true)
376 , changed_attributes_(0)
377 , invisibility_cache_()
386 id_ = cfg[
"id"].str();
391 role_ = cfg[
"role"].str();
394 hidden_ = cfg[
"hidden"].to_bool(
false);
399 side_ = cfg[
"side"].to_int();
410 const vconfig& filter_recall = vcfg->
child(
"filter_recall");
411 if(!filter_recall.
null())
446 deprecated_message(
"[unit]overlays",
DEP_LEVEL::PREEMPTIVE, {1, 17, 0},
"This warning is only triggered by the cases that *do* still work: setting [unit]overlays= works, but the [unit]overlays attribute will always be empty if WML tries to read it.");
449 effect[
"apply_to"] =
"overlay";
450 effect[
"add"] = v->str();
526 if(temp_advances.size() == 1 && temp_advances.front() ==
"null") {
528 }
else if(temp_advances.size() >= 1 && !temp_advances.front().empty()) {
535 for(
config mai :
ai->child_range(
"micro_ai")) {
537 mai.add_child(
"filter")[
"id"] =
id();
538 mai[
"side"] =
side();
539 mai[
"action"] =
"add";
542 for(
config ca :
ai->child_range(
"candidate_action")) {
544 ca.add_child(
"filter_own")[
"id"] =
id();
546 ca.remove_attribute(
"sticky");
547 std::string stage =
"main_loop";
548 if(ca.has_attribute(
"stage")) {
549 stage = ca[
"stage"].str();
550 ca.remove_attribute(
"stage");
555 "path",
"stage[" + stage +
"].candidate_action[]",
556 "candidate_action", ca,
569 for(
const config&
c : cfg_range) {
578 for(
const config&
c : cfg_range) {
626 if(st.second.to_bool()) {
632 if(cfg[
"ai_special"] ==
"guardian") {
653 resting_ = cfg[
"resting"].to_bool();
658 if(!cfg[
"recall_cost"].
blank()) {
672 for(
const auto& anim :
anim_comp_->animations_) {
673 std::cout << anim.debug() << std::endl;
680 for(
auto& u : units_with_cache) {
681 u->clear_visibility_cache();
684 units_with_cache.clear();
718 auto itor = std::find(units_with_cache.begin(), units_with_cache.end(),
this);
720 if(itor != units_with_cache.end()) {
721 units_with_cache.erase(itor);
723 }
catch(
const std::exception &
e) {
724 ERR_UT <<
"Caught exception when destroying unit: " <<
e.what();
741 LOG_UT <<
"Generating a trait for unit type " <<
type().
log_id() <<
" with must_have_only " << must_have_only;
749 const std::string& tid =
t[
"id"];
750 bool already =
false;
751 for(
const config& mod : current_traits) {
752 if(mod[
"id"] == tid) {
761 const std::string& avl =
t[
"availability"];
762 if(avl ==
"musthave") {
773 std::vector<const config*> candidate_traits;
774 std::vector<std::string> temp_require_traits;
775 std::vector<std::string> temp_exclude_traits;
779 int nb_traits = current_traits.size();
781 for(; nb_traits < max_traits; ++nb_traits)
784 candidate_traits.clear();
787 const std::string& tid =
t[
"id"];
788 bool already =
false;
789 for(
const config& mod : current_traits) {
790 if(mod[
"id"] == tid) {
805 for(
const config& mod : current_traits) {
806 if (mod[
"exclude_traits"] !=
"") {
808 temp_exclude_traits.push_back(
c);
814 bool trait_req_met =
true;
815 for(
const std::string&
s : temp_require_traits) {
816 bool has_trait =
false;
817 for(
const config& mod : current_traits) {
822 trait_req_met =
false;
831 bool trait_exc_met =
true;
833 for(
const std::string&
s : temp_exclude_traits) {
834 bool has_exclusionary_trait =
false;
835 for(
const config& mod : current_traits) {
837 has_exclusionary_trait =
true;
840 has_exclusionary_trait =
true;
842 if(has_exclusionary_trait) {
843 trait_exc_met =
false;
851 const std::string& avl =
t[
"availability"];
854 if(!must_have_only && (!
can_recruit() || avl ==
"any")) {
855 candidate_traits.push_back(&
t);
859 if(candidate_traits.empty()) {
865 candidate_traits.
erase(candidate_traits.begin() + num);
874 std::vector<std::string> res;
880 res.push_back(mod[
"id"]);
915 if(!new_type.
usage().empty()) {
920 if(!new_type.
ellipse().empty()) {
965 return std::make_shared<attack_type>(atk);
1052 return leader_crown_path;
1062 double unit_energy = 0.0;
1063 color_t energy_color {0,0,0,255};
1065 if(max_hitpoints > 0) {
1066 unit_energy =
static_cast<double>(hitpoints)/
static_cast<double>(max_hitpoints);
1069 if(1.0 == unit_energy) {
1070 energy_color.r = 33;
1071 energy_color.g = 225;
1073 }
else if(unit_energy > 1.0) {
1074 energy_color.r = 100;
1075 energy_color.g = 255;
1076 energy_color.b = 100;
1077 }
else if(unit_energy >= 0.75) {
1078 energy_color.r = 170;
1079 energy_color.g = 255;
1081 }
else if(unit_energy >= 0.5) {
1082 energy_color.r = 255;
1083 energy_color.g = 175;
1085 }
else if(unit_energy >= 0.25) {
1086 energy_color.r = 255;
1087 energy_color.g = 155;
1090 energy_color.r = 255;
1095 return energy_color;
1115 const color_t near_advance_color {255,255,255,255};
1116 const color_t mid_advance_color {150,255,255,255};
1117 const color_t far_advance_color {0,205,205,255};
1118 const color_t normal_color {0,160,225,255};
1119 const color_t near_amla_color {225,0,255,255};
1120 const color_t mid_amla_color {169,30,255,255};
1121 const color_t far_amla_color {139,0,237,255};
1122 const color_t amla_color {170,0,255,255};
1131 color=near_advance_color;
1132 }
else if(mid_advance){
1133 color=mid_advance_color;
1134 }
else if(far_advance){
1135 color=far_advance_color;
1137 }
else if(has_amla){
1139 color=near_amla_color;
1140 }
else if(mid_advance){
1141 color=mid_amla_color;
1142 }
else if(far_advance){
1143 color=far_amla_color;
1154 bool major_amla =
false;
1155 bool has_amla =
false;
1157 major_amla |= adv[
"major_amla"].to_bool();
1172 std::vector<std::string> result;
1175 result.push_back(adv_type->type_name());
1177 WRN_UT <<
"unknown unit in advances_to list of type "
1210 if(goal_dur.empty()) {
1212 return !mod_dur.empty() && mod_dur !=
"forever";
1215 return mod_dur == goal_dur;
1221 const unit_type* rebuild_from =
nullptr;
1225 for(
const auto& mod_name : ModificationTypes) {
1238 else if(rebuild_from ==
nullptr) {
1239 rebuild_from = &
type();
1247 if(rebuild_from !=
nullptr) {
1312 std::set<std::string> all_states =
states_;
1315 all_states.insert(state.first);
1320 if(all_states.count(
"undrainable") && all_states.count(
"unpoisonable") && all_states.count(
"unplagueable")) {
1321 all_states.insert(
"not_living");
1331 return get_state(known_boolean_state_id);
1335 if(state ==
"not_living") {
1366 {
"slowed", STATE_SLOWED},
1367 {
"poisoned", STATE_POISONED},
1368 {
"petrified", STATE_PETRIFIED},
1369 {
"uncovered", STATE_UNCOVERED},
1370 {
"not_moved", STATE_NOT_MOVED},
1371 {
"unhealable", STATE_UNHEALABLE},
1372 {
"guardian", STATE_GUARDIAN},
1373 {
"invulnerable", STATE_INVULNERABLE},
1381 set_state(known_boolean_state_id, value);
1386 if(state ==
"not_living") {
1402 if(ab.cfg[
"id"] == ability) {
1415 if(
i->cfg[
"id"] == ability) {
1425 if(filter[attribute].empty()) {
1429 return filter[attribute].to_bool() == cfg[attribute].to_bool(def);
1434 if(filter[attribute].empty()) {
1438 const std::vector<std::string> filter_attribute =
utils::split(filter[attribute]);
1439 return ( std::find(filter_attribute.begin(), filter_attribute.end(), cfg[attribute].str(def)) != filter_attribute.end() );
1444 if(filter[attribute].empty()) {
1448 if(cfg[attribute].empty() && (attribute ==
"add" || attribute ==
"sub")){
1449 if(attribute ==
"add"){
1450 return in_ranges<int>(-cfg[
"sub"].to_int(0),
utils::parse_ranges(filter[attribute].str()));
1451 }
else if(attribute ==
"sub"){
1452 return in_ranges<int>(-cfg[
"add"].to_int(0),
utils::parse_ranges(filter[attribute].str()));
1457 return in_ranges<int>(cfg[attribute].to_int(0),
utils::parse_ranges(filter[attribute].str()));
1462 if(filter[attribute].empty()) {
1471 if(filter[
"type_value"].empty()) {
1475 std::string cfg_type_value;
1476 const std::vector<std::string> filter_attribute =
utils::split(filter[
"type_value"]);
1477 if(!cfg[
"value"].empty()){
1478 cfg_type_value =
"value";
1479 }
else if(!cfg[
"add"].empty()){
1480 cfg_type_value =
"add";
1481 }
else if(!cfg[
"sub"].empty()){
1482 cfg_type_value =
"sub";
1483 }
else if(!cfg[
"multiply"].empty()){
1484 cfg_type_value =
"multiply";
1485 }
else if(!cfg[
"divide"].empty()){
1486 cfg_type_value =
"divide";
1488 return ( std::find(filter_attribute.begin(), filter_attribute.end(), cfg_type_value) != filter_attribute.end() );
1493 if(!filter[
"affect_adjacent"].empty()){
1495 bool adjacent = cfg_adjacent ? true :
false;;
1496 if(filter[
"affect_adjacent"].to_bool() != adjacent){
1513 const std::vector<std::string> filter_type =
utils::split(filter[
"tag_name"]);
1514 if ( !filter_type.empty() && std::find(filter_type.begin(), filter_type.end(), tag_name) == filter_type.end() )
1560 if ( condition.key ==
"and" )
1564 else if ( condition.key ==
"or" )
1568 else if ( condition.key ==
"not" )
1590 for(
const auto& a_ptr :
attacks_) {
1591 if(a_ptr->get_changed()) {
1601 auto write_subtag = [&](
const std::string& key,
const config& child)
1605 if(!child.empty()) {
1626 cfg.
add_child(
"special_note")[
"note"] = note;
1631 cfg[
"halo"] = *
halo_;
1658 cfg[
"side"] =
side_;
1671 cfg[
"role"] =
role_;
1674 for(
const std::string& state :
get_states()) {
1675 status_flags[state] =
true;
1680 write_subtag(
"status", status_flags);
1688 cfg[
"overlays"] =
"";
1690 cfg[
"name"] =
name_;
1695 cfg[
"canrecruit"] =
true;
1755 if(!advancement.empty()) {
1756 cfg.
add_child(
"advancement", advancement);
1784 return utils::holds_alternative<upkeep_loyal>(
upkeep_);
1794 if(!defense_abilities.
empty()) {
1804 if(!(cfg[
"active_on"].empty() || (attacker && cfg[
"active_on"] ==
"offense") || (!attacker && cfg[
"active_on"] ==
"defense"))) {
1808 const std::string& apply_to = cfg[
"apply_to"];
1809 if(!apply_to.empty()) {
1810 if(damage_name != apply_to) {
1811 if(apply_to.find(
',') != std::string::npos &&
1812 apply_to.find(damage_name) != std::string::npos) {
1813 const std::vector<std::string>& vals =
utils::split(apply_to);
1814 if(std::find(vals.begin(),vals.end(),damage_name) == vals.end()) {
1839 if(!resistance_abilities.
empty()) {
1842 res = 100 - std::min<int>(
1844 resistance_abilities.
highest(
"max_value").first
1853 std::map<std::string,std::string> temp;
1872 const std::string&
image = adv[
"image"];
1880 const std::string& tt = adv[
"description"];
1893 std::vector<std::pair<std::string, std::string>> temp;
1894 std::pair<std::string, std::string> icon;
1897 icon.first = adv[
"icon"].str();
1898 icon.second = adv[
"description"].str();
1900 for(
unsigned j = 0, j_count =
modification_count(
"advancement", adv[
"id"]); j < j_count; ++j) {
1901 temp.push_back(icon);
1910 std::vector<config> res;
1912 if(adv[
"strict_amla"].to_bool() && !
advances_to_.empty()) {
1915 if(
auto filter = adv.optional_child(
"filter")) {
1921 if(
modification_count(
"advancement", adv[
"id"]) >=
static_cast<unsigned>(adv[
"max_times"].to_int(1))) {
1925 std::vector<std::string> temp_require =
utils::split(adv[
"require_amla"]);
1926 std::vector<std::string> temp_exclude =
utils::split(adv[
"exclude_amla"]);
1928 if(temp_require.empty() && temp_exclude.empty()) {
1933 std::sort(temp_require.begin(), temp_require.end());
1934 std::sort(temp_exclude.begin(), temp_exclude.end());
1936 std::vector<std::string> uniq_require, uniq_exclude;
1938 std::unique_copy(temp_require.begin(), temp_require.end(), std::back_inserter(uniq_require));
1939 std::unique_copy(temp_exclude.begin(), temp_exclude.end(), std::back_inserter(uniq_exclude));
1941 bool exclusion_found =
false;
1942 for(
const std::string&
s : uniq_exclude) {
1943 int max_num = std::count(temp_exclude.begin(), temp_exclude.end(),
s);
1945 if(mod_num >= max_num) {
1946 exclusion_found =
true;
1951 if(exclusion_found) {
1955 bool requirements_done =
true;
1956 for(
const std::string&
s : uniq_require) {
1957 int required_num = std::count(temp_require.begin(), temp_require.end(),
s);
1959 if(required_num > mod_num) {
1960 requirements_done =
false;
1965 if(requirements_done) {
1993 std::size_t res = 0;
1995 if(
item[
"id"] ==
id) {
2001 if(mod_type ==
"advancement") {
2009 "alignment",
"attack",
"defense",
"ellipse",
"experience",
"fearless",
2010 "halo",
"healthy",
"hitpoints",
"image_mod",
"jamming",
"jamming_costs",
"level",
2011 "loyal",
"max_attacks",
"max_experience",
"movement",
"movement_costs",
2012 "new_ability",
"new_advancement",
"new_animation",
"new_attack",
"overlay",
"profile",
2013 "recall_cost",
"remove_ability",
"remove_advancement",
"remove_attacks",
"resistance",
2014 "status",
"type",
"variation",
"vision",
"vision_costs",
"zoc"
2019 if(apply_to ==
"attack") {
2020 std::vector<t_string> attack_names;
2024 bool affected =
a->describe_modification(effect, &desc);
2025 if(affected && !desc.empty()) {
2026 attack_names.emplace_back(
a->name(),
"wesnoth-units");
2029 if(!attack_names.empty()) {
2032 symbols[
"effect_description"] = desc;
2033 return VGETTEXT(
"$attack_list|: $effect_description", symbols);
2035 }
else if(apply_to ==
"hitpoints") {
2036 const std::string& increase_total = effect[
"increase_total"];
2037 if(!increase_total.empty()) {
2039 "<span color=\"$color\">$number_or_percent</span> HP",
2040 {{
"number_or_percent",
utils::print_modifier(increase_total)}, {
"color", increase_total[0] ==
'-' ?
"#f00" :
"#0f0"}});
2043 const std::string& increase = effect[
"increase"];
2044 if(increase.empty()) {
2047 if(apply_to ==
"movement") {
2049 "<span color=\"$color\">$number_or_percent</span> move",
2050 "<span color=\"$color\">$number_or_percent</span> moves",
2051 std::stoi(increase),
2052 {{
"number_or_percent",
utils::print_modifier(increase)}, {
"color", increase[0] ==
'-' ?
"#f00" :
"#0f0"}});
2053 }
else if(apply_to ==
"vision") {
2055 "<span color=\"$color\">$number_or_percent</span> vision",
2056 {{
"number_or_percent",
utils::print_modifier(increase)}, {
"color", increase[0] ==
'-' ?
"#f00" :
"#0f0"}});
2057 }
else if(apply_to ==
"jamming") {
2059 "<span color=\"$color\">$number_or_percent</span> jamming",
2060 {{
"number_or_percent",
utils::print_modifier(increase)}, {
"color", increase[0] ==
'-' ?
"#f00" :
"#0f0"}});
2061 }
else if(apply_to ==
"max_experience") {
2064 "<span color=\"$color\">$number_or_percent</span> XP to advance",
2065 {{
"number_or_percent",
utils::print_modifier(increase)}, {
"color", increase[0] ==
'-' ?
"#0f0" :
"#f00"}});
2066 }
else if(apply_to ==
"max_attacks") {
2068 "<span color=\"$color\">$number_or_percent</span> attack per turn",
2069 "<span color=\"$color\">$number_or_percent</span> attacks per turn",
2070 std::stoi(increase),
2071 {{
"number_or_percent",
utils::print_modifier(increase)}, {
"color", increase[0] ==
'-' ?
"#f00" :
"#0f0"}});
2072 }
else if(apply_to ==
"recall_cost") {
2075 "<span color=\"$color\">$number_or_percent</span> cost to recall",
2076 {{
"number_or_percent",
utils::print_modifier(increase)}, {
"color", increase[0] ==
'-' ?
"#0f0" :
"#f00"}});
2085 if(apply_to ==
"fearless") {
2088 }
else if(apply_to ==
"healthy") {
2091 }
else if(apply_to ==
"profile") {
2105 for(
const config&
c : cfg_range) {
2106 if(!
c[
"remove"].to_bool()) {
2116 }
else if(apply_to ==
"new_attack") {
2119 }
else if(apply_to ==
"remove_attacks") {
2122 return a->matches_filter(effect);
2126 }
else if(apply_to ==
"attack") {
2129 a->apply_modification(effect);
2131 }
else if(apply_to ==
"hitpoints") {
2133 const std::string& increase_hp = effect[
"increase"];
2134 const std::string& increase_total = effect[
"increase_total"];
2135 const std::string& set_hp = effect[
"set"];
2136 const std::string& set_total = effect[
"set_total"];
2139 const bool violate_max = effect[
"violate_maximum"].to_bool();
2141 if(!set_hp.empty()) {
2142 if(set_hp.back() ==
'%') {
2149 if(!set_total.empty()) {
2150 if(set_total.back() ==
'%') {
2157 if(!increase_total.empty()) {
2165 if(effect[
"heal_full"].to_bool()) {
2169 if(!increase_hp.empty()) {
2175 LOG_UT <<
"resetting hp to max";
2182 }
else if(apply_to ==
"movement") {
2183 const bool apply_to_vision = effect[
"apply_to_vision"].to_bool(
true);
2192 const std::string& increase = effect[
"increase"];
2193 if(!increase.empty()) {
2203 if(apply_to_vision) {
2206 }
else if(apply_to ==
"vision") {
2212 const std::string& increase = effect[
"increase"];
2213 if(!increase.empty()) {
2218 }
else if(apply_to ==
"jamming") {
2219 const std::string& increase = effect[
"increase"];
2221 if(!increase.empty()) {
2226 }
else if(apply_to ==
"experience") {
2227 const std::string& increase = effect[
"increase"];
2228 const std::string&
set = effect[
"set"];
2231 if(
set.back() ==
'%') {
2238 if(increase.empty() ==
false) {
2241 }
else if(apply_to ==
"max_experience") {
2242 const std::string& increase = effect[
"increase"];
2243 const std::string&
set = effect[
"set"];
2245 if(
set.empty() ==
false) {
2246 if(
set.back() ==
'%') {
2253 if(increase.empty() ==
false) {
2258 }
else if(apply_to ==
"status") {
2259 const std::string& add = effect[
"add"];
2260 const std::string&
remove = effect[
"remove"];
2277 }
else if(apply_to ==
"zoc") {
2282 }
else if(apply_to ==
"new_ability") {
2293 }
else if(apply_to ==
"remove_ability") {
2303 }
else if(apply_to ==
"image_mod") {
2304 LOG_UT <<
"applying image_mod";
2305 std::string mod = effect[
"replace"];
2309 LOG_UT <<
"applying image_mod";
2310 mod = effect[
"add"].str();
2320 LOG_UT <<
"applying image_mod";
2321 }
else if(apply_to ==
"new_animation") {
2322 anim_comp_->apply_new_animation_effect(effect);
2323 }
else if(apply_to ==
"ellipse") {
2325 }
else if(apply_to ==
"halo") {
2327 }
else if(apply_to ==
"overlay") {
2328 const std::string& add = effect[
"add"];
2329 const std::string& replace = effect[
"replace"];
2330 const std::string&
remove = effect[
"remove"];
2342 if(add.empty() &&
remove.empty() && !replace.empty()) {
2345 }
else if(apply_to ==
"new_advancement") {
2346 const std::string& types = effect[
"types"];
2347 const bool replace = effect[
"replace"].to_bool(
false);
2350 if(!types.empty()) {
2355 std::copy(temp_advances.begin(), temp_advances.end(), std::back_inserter(
advances_to_));
2368 }
else if(apply_to ==
"remove_advancement") {
2369 const std::string& types = effect[
"types"];
2370 const std::string& amlas = effect[
"amlas"];
2375 for(
const std::string&
unit : temp_advances) {
2385 if(std::find(temp_advances.begin(), temp_advances.end(),
advancements_[
i][
"id"]) != temp_advances.end()) {
2389 }
else if(apply_to ==
"alignment") {
2394 }
else if(apply_to ==
"max_attacks") {
2395 const std::string& increase = effect[
"increase"];
2397 if(!increase.empty()) {
2400 }
else if(apply_to ==
"recall_cost") {
2401 const std::string& increase = effect[
"increase"];
2402 const std::string&
set = effect[
"set"];
2407 if(
set.back() ==
'%') {
2414 if(!increase.empty()) {
2417 }
else if(effect[
"apply_to"] ==
"variation") {
2419 assert(base_type !=
nullptr);
2420 const std::string& variation_id = effect[
"name"];
2424 if(effect[
"heal_full"].to_bool(
false)) {
2428 WRN_UT <<
"unknown variation '" << variation_id <<
"' (name=) in [effect]apply_to=variation, ignoring";
2430 }
else if(effect[
"apply_to"] ==
"type") {
2431 std::string prev_type = effect[
"prev_type"];
2432 if(prev_type.empty()) {
2435 const std::string& new_type_id = effect[
"name"];
2440 if(effect[
"heal_full"].to_bool(
false)) {
2444 WRN_UT <<
"unknown type '" << new_type_id <<
"' (name=) in [effect]apply_to=type, ignoring";
2446 }
else if(effect[
"apply_to"] ==
"level") {
2447 const std::string& increase = effect[
"increase"];
2448 const std::string&
set = effect[
"set"];
2455 level_ = lexical_cast_default<int>(
set);
2458 if(!increase.empty()) {
2459 level_ += lexical_cast_default<int>(increase);
2466 bool generate_description = mod[
"generate_description"].to_bool(
true);
2468 if(no_add ==
false) {
2472 bool set_poisoned =
false;
2473 config type_effect, variation_effect;
2474 std::vector<t_string> effects_description;
2477 if(
auto afilter = effect.optional_child(
"filter")) {
2483 const std::string& apply_to = effect[
"apply_to"];
2484 int times = effect[
"times"].to_int(1);
2487 if(effect[
"times"] ==
"per level") {
2488 if(effect[
"apply_to"] ==
"level") {
2489 WRN_UT <<
"[effect] times=per level is not allowed with apply_to=level, using default value of 1";
2503 if(apply_to ==
"type") {
2504 set_poisoned =
false;
2505 type_effect = effect;
2508 if(apply_to ==
"variation") {
2509 set_poisoned =
false;
2510 variation_effect = effect;
2514 std::string description_component;
2525 description += description_component;
2528 set_poisoned =
true;
2530 set_poisoned =
false;
2541 if(effect[
"times"] ==
"per level" && !times) {
2542 description =
VGETTEXT(
"$effect_description per level", {{
"effect_description", description}});
2545 if(!description.
empty()) {
2546 effects_description.push_back(description);
2550 if((!type_effect.
empty() || !variation_effect.
empty()) && no_add ==
false) {
2551 if(!type_effect.
empty()) {
2552 std::string description;
2559 effects_description.push_back(description);
2561 if(!variation_effect.
empty()) {
2562 std::string description;
2569 effects_description.push_back(description);
2579 const t_string& mod_description = mod[
"description"];
2580 if(!mod_description.
empty()) {
2581 description = mod_description;
2586 if(generate_description && !effects_description.empty()) {
2587 if(!mod_description.
empty()) {
2588 description +=
"\n";
2591 for(
const auto& desc_line : effects_description) {
2592 description += desc_line +
"\n";
2597 if(mod_type ==
"trait") {
2609 const t_string name = gender_specific_name.
empty() ? trait[
"name"] : gender_specific_name;
2643 DBG_UT <<
"unit::invisible called: id = " <<
id() <<
" loc = " << loc <<
" get_loc = " <<
get_location();
2660 return itor->second;
2665 static const std::string hides(
"hides");
2674 units_with_cache.push_back(
this);
2735 std::stringstream ss;
2753 std::string::size_type pos =
id_.find_last_of(
'-');
2754 if(pos != std::string::npos && pos+1 <
id_.size()
2755 &&
id_.find_first_not_of(
"0123456789", pos+1) == std::string::npos) {
2757 WRN_UT <<
"assigning new id to clone of generic unit " <<
id_;
2767 : u_(const_cast<
unit&>(u))
2768 , moves_(u.movement_left(true))
2784 DBG_UT <<
"The unit to be removed is not in the unit map.";
2865 }
catch(std::invalid_argument&
e) {
2866 WRN_UT <<
"Found invalid upkeep=\"" <<
e.what() <<
"\" in a unit";
2879 for(
const auto& a_ptr :
attacks_) {
2880 a_ptr->set_changed(
false);
2894 u.
write(unit_config);
2896 static const std::set<std::string_view> main_keys {
2903 "ignore_race_traits",
2904 "ignore_global_traits",
2921 for(
const std::string_view& main_key : main_keys) {
2922 wcfg[main_key] = unit_config[main_key];
2925 static const std::set<std::string_view> attack_keys {
2936 for(
const std::string_view& attack_key : attack_keys) {
2937 child[attack_key] = att[attack_key];
2970 static const std::set<std::string_view> child_keys {
2979 for(
const std::string_view& child_key : child_keys) {
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands.
void append_active_ai_for_side(ai::side_number side, const config &cfg)
Appends AI parameters to active AI of the given side.
static manager & get_singleton()
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
void append(const config &cfg)
Append data from another config object to this one.
all_children_iterator erase(const all_children_iterator &i)
const_all_children_iterator ordered_begin() const
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
void recursive_clear_value(config_key_type key)
void remove_child(config_key_type key, std::size_t index)
const_attr_itors attribute_range() const
std::size_t child_count(config_key_type key) const
const_all_children_iterator ordered_end() const
void clear_children(T... keys)
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
bool has_attribute(config_key_type key) const
const_all_children_itors all_children_range() const
In-order iteration over all children.
child_itors child_range(config_key_type key)
boost::iterator_range< const_attribute_iterator > const_attr_itors
std::size_t all_children_count() const
attribute_map::value_type attribute
boost::iterator_range< const_child_iterator > const_child_itors
void append_children(const config &cfg)
Adds children from cfg.
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Euivalent to mandatory_child, but returns an empty optional if the nth child was not found.
config & add_child(config_key_type key)
bool would_be_discovered(const map_location &loc, int side_num, bool see_all=true)
Given a location and a side number, indicates whether an invisible unit of that side at that location...
static display * get_singleton()
Returns the display object if a display object exists.
n_unit::id_manager & unit_id_manager()
static game_config_view wrap(const config &cfg)
@ INITIAL
creating intitial [unit]s, executing toplevel [lua] etc.
void add_events(const config::const_child_itors &cfgs, game_lua_kernel &lk, const std::string &type=std::string())
std::string apply_effect(const std::string &name, unit &u, const config &cfg, bool need_apply)
void write(config &cfg, bool include_notes) const
Writes the movement type data to the provided config.
static const std::set< std::string > effects
The set of applicable effects for movement types.
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...
int defense_modifier(const t_translation::terrain_code &terrain) const
Returns the defensive value of the indicated terrain.
int resistance_against(const attack_type &attack) const
Returns the resistance against the indicated attack.
static id_manager & global_instance()
unit_id next_id()
returns id for unit that is created
static rng & default_instance()
int get_random_int(int min, int max)
This class stores all the data for a single 'side' (in game nomenclature).
bool is_enemy(int n) const
static std::string get_side_color_id(unsigned side)
bool fogged(const map_location &loc) const
Visitor helper class to parse the upkeep value from a config.
Visitor helper class to fetch the appropriate upkeep value.
int get_composite_value() const
std::pair< int, map_location > highest(const std::string &key, int def=0) const
const std::string & id() const
static const unit_race null_race
Dummy race used when a race is not yet known.
std::string generate_name(GENDER gender) const
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
const unit_race * find_race(const std::string &) const
void check_types(const std::vector< std::string > &types) const
A single unit type that the player may recruit.
std::vector< t_string > direct_special_notes() const
Returns only the notes defined by [unit_type][special_note] tags, excluding any that would be found f...
const std::string & parent_id() const
The id of the original type from which this (variation) descended.
const std::string & image() const
config::const_child_itors advancements() const
const std::string & variation_id() const
The id of this variation; empty if it's a gender variation or a base unit.
const std::string & id() const
The id for this unit_type.
const movetype & movement_type() const
const unit_race * race() const
Never returns nullptr, but may point to the null race.
double xp_bar_scaling() const
const std::string & default_variation() const
const unit_type & get_variation(const std::string &id) const
const_attack_itors attacks() const
const std::string & usage() const
config::const_child_itors events() const
const std::vector< std::string > & advances_to() const
A vector of unit_type ids that this unit_type can advance to.
bool has_variation(const std::string &variation_id) const
std::string ellipse() const
t_string unit_description() const
static void check_id(std::string &id)
Validate the id argument.
const std::string & flag_rgb() const
const config & abilities_cfg() const
const std::string log_id() const
A variant on id() that is more descriptive, for use with message logging.
const unit_type & get_gender_unit_type(std::string gender) const
Returns a gendered variant of this unit_type.
const std::string & icon() const
int experience_needed(bool with_acceleration=true) const
bool generate_name() const
const std::string & big_profile() const
const std::string & undead_variation() const
Info on the type of unit that the unit reanimates as.
double hp_bar_scaling() const
const t_string & type_name() const
The name of the unit in the current language setting.
config::const_child_itors possible_traits() const
unit_alignments::type alignment() const
const std::string & small_profile() const
const config & get_cfg() const
unsigned int num_traits() const
This class represents a single unit of a specific type.
static void clear_status_caches()
Clear this unit status cache for all units.
void set_attr_changed(UNIT_ATTRIBUTE attr)
bool get_attr_changed(UNIT_ATTRIBUTE attr) const
void clear_changed_attributes()
void init(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
static const std::string & leader_crown()
The path to the leader crown overlay.
bool get_attacks_changed() const
A variable-expanding proxy for the config class.
std::vector< vconfig > child_list
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
const config & get_config() const
child_list get_children(const std::string &key) const
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Interfaces for manipulating version numbers of engine, add-ons, etc.
void generate_name()
Generates a random race-appropriate name if one has not already been provided.
std::vector< t_string > trait_names_
~unit_movement_resetter()
void remove_ability_by_attribute(const config &filter)
Removes a unit's abilities with a specific ID or other attribute.
std::string undead_variation_
t_string type_name_
The displayed name of this unit type.
std::optional< std::string > ellipse_
map_location::DIRECTION facing_
unit_movement_resetter(const unit_movement_resetter &)=delete
void write(config &cfg, bool write_all=true) const
Serializes the current unit metadata values.
std::bitset< UA_COUNT > changed_attributes_
std::string small_profile_
void write_upkeep(config::attribute_value &upkeep) const
bool get_ability_bool(const std::string &tag_name, const map_location &loc) const
Checks whether this unit currently possesses or is affected by a given ability.
std::vector< t_string > special_notes_
static std::map< std::string, state_t > known_boolean_state_names_
unit_ability_list get_abilities_weapons(const std::string &tag_name, const map_location &loc, const_attack_ptr weapon=nullptr, const_attack_ptr opp_weapon=nullptr) const
const unit_type * type_
Never nullptr.
std::bitset< num_bool_states > known_boolean_states_
const unit_race * race_
Never nullptr, but may point to the null race.
unit_alignments::type alignment_
bool invisible(const map_location &loc, bool see_all=true) const
bool is_visible_to_team(const team &team, bool const see_all=true) const
n_unit::unit_id underlying_id_
unit & mark_clone(bool is_temporary)
Mark this unit as clone so it can be inserted to unit_map.
unit_ability_list get_abilities(const std::string &tag_name, const map_location &loc) const
Gets the unit's active abilities of a particular type if it were on a specified location.
unit_race::GENDER gender_
std::map< map_location, bool > invisibility_cache_
Hold the visibility status cache for a unit, when not uncovered.
std::vector< std::string > advances_to_
std::unique_ptr< unit_animation_component > anim_comp_
static std::string type()
void remove_ability_by_id(const std::string &ability)
Removes a unit's abilities with a specific ID.
std::vector< std::string > overlays_
bool has_ability_by_id(const std::string &ability) const
Check if the unit has an ability of a specific ID.
const config & abilities() const
void parse_upkeep(const config::attribute_value &upkeep)
std::vector< std::string > recruit_list_
std::vector< config > advancements_
utils::string_map modification_descriptions_
unit_checksum_version
Optional parameter for get_checksum to use the algorithm of an older version of Wesnoth,...
std::set< std::string > states_
std::optional< std::string > halo_
bool ability_matches_filter(const config &cfg, const std::string &tag_name, const config &filter) const
Verify what abilities attributes match with filter.
std::unique_ptr< unit_formula_manager > formula_man_
std::vector< t_string > trait_descriptions_
std::optional< std::string > usage_
@ version_1_16_or_older
Included some of the flavortext from weapon specials.
void set_big_profile(const std::string &value)
int max_hitpoints() const
The max number of hitpoints this unit can have.
void heal(int amount)
Heal the unit.
void set_state(const std::string &state, bool value)
Set whether the unit is affected by a status effect.
void new_turn()
Refresh unit for the beginning of a turn.
const std::vector< std::string > & recruits() const
The type IDs of the other units this unit may recruit, if possible.
void set_max_experience(int value)
void set_max_hitpoints(int value)
int recall_cost() const
How much gold it costs to recall this unit, or -1 if the side's default recall cost is used.
std::string big_profile() const
An optional profile image displays when this unit is 'speaking' via [message].
static state_t get_known_boolean_state_id(const std::string &state)
Convert a string status effect ID to a built-in status effect ID.
void set_level(int level)
Sets the current level of this unit.
void set_hidden(bool state) const
Sets whether the unit is hidden on the map.
const std::string & variation() const
The ID of the variation of this unit's type.
int hitpoints() const
The current number of hitpoints this unit has.
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
std::string small_profile() const
An optional profile image to display in Help.
void heal_fully()
Fully heal the unit, restoring it to max hitpoints.
void set_undead_variation(const std::string &value)
The ID of the undead variation (ie, dwarf, swimmer) of this unit.
const std::string & type_id() const
The id of this unit's type.
void set_alignment(unit_alignments::type alignment)
Sets the alignment of this unit.
const std::set< std::string > get_states() const
Get the status effects currently affecting the unit.
void new_scenario()
Refresh unit for the beginning of a new scenario.
void end_turn()
Refresh unit for the end of a turn.
const unit_type & type() const
This unit's type, accounting for gender and variation.
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
const std::string & id() const
Gets this unit's id.
void set_underlying_id(n_unit::id_manager &id_manager)
Sets the internal ID.
int side() const
The side this unit belongs to.
unsigned int experience_to_advance() const
The number of experience points this unit needs to level up, or 0 if current XP > max XP.
state_t
Built-in status effects known to the engine.
void set_recruits(const std::vector< std::string > &recruits)
Sets the recruit list.
std::vector< t_string > unit_special_notes() const
The unit's special notes.
config & variables()
Gets any user-defined variables this unit 'owns'.
void set_usage(const std::string &usage)
Sets this unit's usage.
void set_small_profile(const std::string &value)
unit_race::GENDER gender() const
The gender of this unit.
const t_string & name() const
Gets this unit's translatable display name.
@ STATE_UNKNOWN
To set the size of known_boolean_states_.
@ STATE_NOT_MOVED
The unit is uncovered - it was hiding but has been spotted.
@ STATE_GUARDIAN
The unit cannot be healed.
@ STATE_INVULNERABLE
The unit is a guardian - it won't move unless a target is sighted.
@ STATE_PETRIFIED
The unit is poisoned - it loses health each turn.
@ STATE_POISONED
The unit is slowed - it moves slower and does less damage.
@ STATE_UNCOVERED
The unit is petrified - it cannot move or be attacked.
std::vector< std::string > advances_to_t
std::vector< config > get_modification_advances() const
Gets any non-typed advanced options set by modifications.
std::vector< std::pair< std::string, std::string > > amla_icons() const
Gets the image and description data for modification advancements.
const advances_to_t & advances_to() const
Gets the possible types this unit can advance to on level-up.
bool can_advance() const
Checks whether this unit has any options to advance to.
void set_advancements(std::vector< config > advancements)
Sets the raw modification advancement option data.
void set_advances_to(const std::vector< std::string > &advances_to)
Sets this unit's advancement options.
const std::vector< config > & modification_advancements() const
The raw, unparsed data for modification advancements.
std::map< std::string, std::string > advancement_icons() const
Gets and image path and and associated description for each advancement option.
const std::vector< std::string > advances_to_translated() const
Gets the names of the possible types this unit can advance to on level-up.
void advance_to(const unit_type &t, bool use_traits=false)
Advances this unit to another type.
void remove_attacks_ai()
Set the unit to have no attacks left for this turn.
bool resistance_filter_matches(const config &cfg, bool attacker, const std::string &damage_name, int res) const
void set_max_attacks(int value)
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
bool remove_attack(attack_ptr atk)
Remove an attack from the unit.
attack_itors attacks()
Gets an iterator over this unit's attacks.
int resistance_against(const std::string &damage_name, bool attacker, const map_location &loc, const_attack_ptr weapon=nullptr, const_attack_ptr opp_weapon=nullptr) const
The unit's resistance against a given damage type.
void set_attacks(int left)
Sets the number of attacks this unit has left this turn.
color_t xp_color() const
Color for this unit's XP.
color_t hp_color() const
Color for this unit's current hitpoints.
std::string TC_image_mods() const
Constructs a recolor (RC) IPF string for this unit's team color.
static color_t hp_color_max()
const std::string & flag_rgb() const
Get the source color palette to use when recoloring the unit's image.
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
std::string default_anim_image() const
The default image to use for animation frames with no defined image.
const std::vector< std::string > & overlays() const
Get the unit's overlay images.
std::string absolute_image() const
The name of the file to game_display (used in menus).
void set_image_ellipse(const std::string &ellipse)
Set the unit's ellipse image.
void set_image_halo(const std::string &halo)
Set the unit's halo image.
void apply_builtin_effect(std::string type, const config &effect)
Apply a builtin effect to the unit.
void add_modification(const std::string &type, const config &modification, bool no_add=false)
Add a new modification to the unit.
static const std::set< std::string > builtin_effects
std::string describe_builtin_effect(std::string type, const config &effect)
Construct a string describing a built-in effect.
void apply_modifications()
Re-apply all saved modifications.
void expire_modifications(const std::string &duration)
Clears those modifications whose duration has expired.
std::size_t modification_count(const std::string &type, const std::string &id) const
Count modifications of a particular type.
const map_location & get_location() const
The current map location this unit is at.
void set_facing(map_location::DIRECTION dir) const
The this unit's facing.
const movetype & movement_type() const
Get the unit's movement type.
void set_movement(int moves, bool unit_action=false)
Set this unit's remaining movement to moves.
void set_total_movement(int value)
void set_emit_zoc(bool val)
Sets the raw zone-of-control flag.
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
int total_movement() const
The maximum moves this unit has.
void remove_movement_ai()
Sets the unit to have no moves left for this turn.
void set_interrupted_move(const map_location &interrupted_move)
Set the target location of the unit's interrupted move.
int upkeep() const
Gets the amount of gold this unit costs a side per turn.
void add_trait_description(const config &trait, const t_string &description)
Register a trait's name and its description for the UI's use.
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has.
void generate_traits(bool must_have_only=false)
Applies mandatory traits (e.g.
bool loyal() const
Gets whether this unit is loyal - ie, it costs no upkeep.
std::string tooltip
Shown when hovering over an entry in the filter's drop-down list.
New lexcical_cast header.
Standard logging facilities (interface).
#define log_scope(description)
A small explanation about what's going on here: Each action has access to two game_info objects First...
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Handling of system events.
static void add_color_info(const game_config_view &v, bool build_defaults)
void remove()
Removes a tip.
std::pair< std::string, unsigned > item
Functions to load and save images from/to disk.
Main entry points of multiplayer mode.
std::set< std::string > & encountered_units()
rng * generator
This generator is automatically synced during synced context.
game_events::manager * game_events
game_lua_kernel * lua_kernel
filter_context * filter_con
bool filter_base_matches(const config &cfg, int def)
std::vector< std::pair< int, int > > parse_ranges(const std::string &str)
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
std::vector< std::string > parenthetical_split(const std::string &val, const char separator, const std::string &left, const std::string &right, const int flags)
Splits a string based either on a separator, except then the text appears within specified parenthesi...
void erase_if(Container &container, const Predicate &predicate)
Convenience wrapper for using std::remove_if on a container.
int apply_modifier(const int number, const std::string &amount, const int minimum)
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::vector< std::pair< double, double > > parse_ranges_real(const std::string &str)
std::string format_conjunct_list(const t_string &empty, const std::vector< t_string > &elems)
Format a conjunctive list.
std::map< std::string, t_string > string_map
std::vector< std::string > split(const config_attribute_value &val)
std::string print_modifier(const std::string &mod)
Add a "+" or replace the "-" par Unicode minus.
std::string::const_iterator iterator
std::shared_ptr< const attack_type > const_attack_ptr
std::shared_ptr< attack_type > attack_ptr
const std::string & gender_string(unit_race::GENDER gender)
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
const config::attribute_value & gender_value(const config &cfg, unit_race::GENDER gender, const std::string &male_key, const std::string &female_key, const std::string &default_key)
Chooses a value from the given config based on gender.
The basic class for representing 8-bit RGB or RGBA colour values.
Encapsulates the map of the game.
static DIRECTION parse_direction(const std::string &str)
DIRECTION
Valid directions which can be moved in our hexagonal world.
static std::string write_direction(DIRECTION dir)
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
static constexpr std::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Visitor helper struct to fetch the upkeep type flag if applicable, or the the value otherwise.
Data typedef for unit_ability_list.
void validate_side(int side)
static map_location::DIRECTION s
unit_type_data unit_types
std::vector< t_string > combine_special_notes(const std::vector< t_string > direct, const config &abilities, const_attack_itors attacks, const movetype &mt)
Common logic for unit_type::special_notes() and unit::special_notes().
void adjust_profile(std::string &profile)
static lg::log_domain log_unit("unit")
static bool type_value_if_present(const config &filter, const config &cfg)
static bool matches_ability_filter(const config &cfg, const std::string &tag_name, const config &filter)
static const unit_type & get_unit_type(const std::string &type_id)
Converts a string ID to a unit_type.
static bool bool_matches_if_present(const config &filter, const config &cfg, const std::string &attribute, bool def)
static unit_race::GENDER generate_gender(const unit_type &type, bool random_gender)
bool mod_duration_match(const std::string &mod_dur, const std::string &goal_dur)
Determines if mod_dur "matches" goal_dur.
static bool double_matches_if_present(const config &filter, const config &cfg, const std::string &attribute)
static bool string_matches_if_present(const config &filter, const config &cfg, const std::string &attribute, const std::string &def)
std::string get_checksum(const unit &u, backwards_compatibility::unit_checksum_version version)
Gets a checksum for a unit.
static color_t hp_color_impl(int hitpoints, int max_hitpoints)
static bool int_matches_if_present(const config &filter, const config &cfg, const std::string &attribute)