The Battle for Wesnoth  1.19.13+dev
unit_preview_pane.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2025
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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
20 #include "gui/widgets/button.hpp"
21 #include "gui/widgets/drawing.hpp"
22 #include "gui/widgets/image.hpp"
23 #include "gui/widgets/label.hpp"
26 
27 #include "formatter.hpp"
28 #include "formula/string_utils.hpp"
29 #include "language.hpp"
31 #include "gettext.hpp"
32 #include "help/help.hpp"
33 #include "help/help_impl.hpp"
34 #include "play_controller.hpp"
35 #include "resources.hpp"
36 #include "serialization/markup.hpp"
37 #include "team.hpp"
38 #include "terrain/movement.hpp"
39 #include "terrain/type_data.hpp"
40 #include "units/types.hpp"
41 #include "units/helper.hpp"
42 #include "units/unit.hpp"
43 #include "wml_exception.hpp"
44 
45 #include <functional>
46 
47 namespace gui2
48 {
49 
50 // ------------ WIDGET -----------{
51 
52 REGISTER_WIDGET(unit_preview_pane)
53 
54 unit_preview_pane::unit_preview_pane(const implementation::builder_unit_preview_pane& builder)
55  : container_base(builder, type())
56  , current_type_()
57  , icon_type_(nullptr)
58  , icon_race_(nullptr)
59  , icon_alignment_(nullptr)
60  , label_name_(nullptr)
61  , label_level_(nullptr)
62  , label_race_(nullptr)
63  , label_details_(nullptr)
64  , tree_details_(nullptr)
65  , button_profile_(nullptr)
66  , image_mods_(builder.image_mods)
67 {
68 }
69 
71 {
72  // Icons
73  icon_type_ = find_widget<drawing>("type_image", false, false);
74  icon_race_ = find_widget<image>("type_race", false, false);
75  icon_alignment_ = find_widget<image>("type_alignment", false, false);
76 
77  // Labels
78  label_name_ = find_widget<label>("type_name", false, false);
79  label_level_ = find_widget<label>("type_level", false, false);
80  label_race_ = find_widget<label>("type_race_label", false, false);
81  label_details_ = find_widget<styled_widget>("type_details_minimal", false, false);
82 
83  tree_details_ = find_widget<tree_view>("type_details", false, false);
84 
85  // Profile button
86  button_profile_ = find_widget<button>("type_profile", false, false);
87 
88  if(button_profile_) {
91  }
92 }
93 
94 static inline tree_view_node& add_name_tree_node(tree_view_node& header_node, const std::string& type, const t_string& label, const t_string& tooltip = "")
95 {
96  /* Note: We have to pass data instead of just doing 'child_label.set_label(label)' below
97  * because the tree_view_node::add_child needs to have the correct size of the
98  * node child widgets for its internal size calculations.
99  * Same is true for 'use_markup'
100  */
101  auto& child_node = header_node.add_child(type, { { "name",{ { "label", label },{ "use_markup", "true" } } } });
102  auto& child_label = child_node.find_widget<styled_widget>("name", true);
103 
104  child_label.set_tooltip(tooltip);
105  return child_node;
106 }
107 
108 static inline std::string get_hp_tooltip(
109  const utils::string_map_res& res, const std::function<int(const std::string&, bool)>& get)
110 {
111  std::ostringstream tooltip;
112 
113  std::vector<std::string> resistances_table;
114 
115  bool att_def_diff = false;
116  for(const utils::string_map_res::value_type &resist : res) {
117  std::ostringstream line;
118  line << translation::dgettext("wesnoth", resist.first.c_str()) << ": ";
119 
120  // Some units have different resistances when attacking or defending.
121  const int res_att = 100 - get(resist.first, true);
122  const int res_def = 100 - get(resist.first, false);
123 
124  if(res_att == res_def) {
126  } else {
129  att_def_diff = true;
130  }
131 
132  resistances_table.push_back(line.str());
133  }
134 
135  tooltip << markup::tag("big", _("Resistances: "));
136  if(att_def_diff) {
137  tooltip << _("(Att / Def)");
138  }
139 
140  for(const std::string &line : resistances_table) {
141  tooltip << '\n' << font::unicode_bullet << " " << line;
142  }
143 
144  return tooltip.str();
145 }
146 
147 static inline std::string get_mp_tooltip(int total_movement, const std::function<int (t_translation::terrain_code)>& get)
148 {
149  std::set<terrain_movement> terrain_moves;
150  std::ostringstream tooltip;
151  tooltip << markup::tag("big", _("Movement Costs:"));
152 
153  std::shared_ptr<terrain_type_data> tdata = help::load_terrain_types_data();
154 
155  if(!tdata) {
156  return "";
157  }
158 
159  for(t_translation::terrain_code terrain : prefs::get().encountered_terrains()) {
161  continue;
162  }
163 
164  const terrain_type& info = tdata->get_terrain_info(terrain);
165  if(info.is_indivisible() && info.is_nonnull()) {
166  terrain_moves.emplace(info.name(), get(terrain));
167  }
168  }
169 
170  for(const terrain_movement& tm: terrain_moves)
171  {
172  tooltip << '\n' << font::unicode_bullet << " " << tm.name << ": ";
173 
174  // movement - range: 1 .. 5, movetype::UNREACHABLE=impassable
175  const bool cannot_move = tm.moves > total_movement; // cannot move in this terrain
176  double movement_red_to_green = 100.0 - 25.0 * tm.moves;
177 
178  std::stringstream move_ss;
179  // A 5 MP margin; if the movement costs go above the unit's max moves + 5, we replace it with dashes.
180  if(cannot_move && (tm.moves > total_movement + 5)) {
181  move_ss << font::unicode_figure_dash;
182  } else if (cannot_move) {
183  move_ss << "(" << tm.moves << ")";
184  } else {
185  move_ss << tm.moves;
186  }
187  if(tm.moves != 0) {
188  const int movement_hexes_per_turn = total_movement / tm.moves;
189  tooltip << " ";
190  for(int i = 0; i < movement_hexes_per_turn; ++i) {
191  // Unicode horizontal black hexagon and Unicode zero width space (to allow a line break)
192  move_ss << "\u2b23\u200b";
193  }
194  }
195 
196  // passing true to select the less saturated red-to-green scale
197  tooltip << markup::span_color(game_config::red_to_green(movement_red_to_green, true), move_ss.str());
198  }
199 
200  return tooltip.str();
201 }
202 
203 /*
204  * Both unit and unit_type use the same format (vector of attack_types) for their
205  * attack data, meaning we can keep this as a helper function.
206  */
207 template<typename T>
209  T attacks,
210  const int attacks_left,
211  const int max_attacks,
212  tree_view_node& parent_node)
213 {
214  if(attacks.empty()) {
215  return;
216  }
217 
218  auto& header_node = add_name_tree_node(parent_node, "header", markup::bold(_("Attacks")));
219 
220  if(max_attacks > 1) {
221  add_name_tree_node(header_node, "item",
222  VGETTEXT("Remaining: $left/$max",
223  {{"left", std::to_string(attacks_left)},
224  {"max", std::to_string(max_attacks)}}),
225  _("This unit can attack multiple times per turn."));
226  }
227 
228  for(const auto& a : attacks) {
229  const std::string range_png = std::string("icons/profiles/") + a.range() + "_attack.png~SCALE_INTO(16,16)";
230  const std::string type_png = std::string("icons/profiles/") + a.type() + ".png~SCALE_INTO(16,16)";
231  const bool range_png_exists = ::image::exists(range_png);
232  const bool type_png_exists = ::image::exists(type_png);
233 
234  const t_string& range = string_table["range_" + a.range()];
235  const t_string& type = string_table["type_" + a.type()];
236 
237  const std::string dmg_label = markup::span_color(
238  font::unit_type_color, a.damage(), font::weapon_numbers_sep, a.num_attacks(), " ", a.name());
239 
240  auto& subsection = header_node.add_child(
241  "item_image",
242  {
243  { "image_range", { { "label", range_png } } },
244  { "image_type", { { "label", type_png } } },
245  { "name", { { "label", dmg_label }, { "use_markup", "true" } } },
246  }
247  );
248 
249  subsection.find_widget<styled_widget>("image_range", true).set_tooltip(range);
250  subsection.find_widget<styled_widget>("image_type", true).set_tooltip(type);
251 
252  if(!range_png_exists || !type_png_exists) {
254  subsection,
255  "item",
257  );
258  }
259 
260  const std::string acc_parry_str = a.accuracy_parry_description();
261  if(!acc_parry_str.empty()) {
263  subsection,
264  "item",
266  a.accuracy_parry_tooltip()
267  );
268  }
269 
270  if(max_attacks > 1) {
272  subsection,
273  "item",
276  VNGETTEXT(
277  "uses $num attack",
278  "uses $num attacks",
279  a.attacks_used(),
280  { {"num", std::to_string(a.attacks_used())} }))
281  );
282  }
283 
284  for(const auto& pair : a.special_tooltips()) {
286  subsection,
287  "item",
289  markup::span_size("x-large", pair.first) + "\n" + pair.second
290  );
291  }
292  }
293 }
294 
295 void unit_preview_pane::set_display_data(const unit_type& type)
296 {
297  // Sets the current type id for the profile button callback to use
298  current_type_ = type;
299 
300  if(icon_type_) {
301  std::string mods;
302 
304  mods = "~RC(" + type.flag_rgb() + ">" +
306  + ")";
307  }
308 
309  mods += image_mods_;
310 
311  icon_type_->set_label((type.icon().empty() ? type.image() : type.icon()) + mods);
312  }
313 
314  if(label_name_) {
315  label_name_->set_label(markup::bold(type.type_name()));
316  label_name_->set_use_markup(true);
317  }
318 
319  if(label_level_) {
320  std::string l_str = VGETTEXT("Lvl $lvl", {{"lvl", std::to_string(type.level())}});
321 
322  label_level_->set_label(markup::bold(l_str));
323  label_level_->set_tooltip(unit_helper::unit_level_tooltip(type));
324  label_level_->set_use_markup(true);
325  }
326 
327  if(label_race_) {
328  label_race_ ->set_label(type.race()->name(type.genders().front()));
329  }
330 
331  if(icon_race_) {
332  icon_race_->set_label(type.race()->get_icon_path_stem() + "_30.png");
333  }
334 
335  if(icon_alignment_) {
336  const std::string& alignment_name = unit_alignments::get_string(type.alignment());
337 
338  icon_alignment_->set_label("icons/alignments/alignment_" + alignment_name + "_30.png");
339  icon_alignment_->set_tooltip(unit_type::alignment_description(
340  type.alignment(),
341  type.genders().front()));
342  }
343 
344  if(label_details_) {
345  std::stringstream str;
346 
347  str << " \n";
348 
349  str << markup::span_color(font::unit_type_color, type.type_name()) << "\n";
350 
351  std::string l_str = VGETTEXT("Lvl $lvl", {{"lvl", std::to_string(type.level())}});
352  str << l_str << "\n";
353 
354  str << unit_alignments::get_string(type.alignment()) << "\n";
355 
356  str << "\n"; // Leave a blank line where traits would be
357 
358  str << _("HP: ") << type.hitpoints() << "\n";
359 
360  str << _("XP: ") << type.experience_needed(true);
361 
362  label_details_->set_label(str.str());
363  label_details_->set_use_markup(true);
364  }
365 
366  if(tree_details_) {
367 
368  tree_details_->clear();
369  tree_details_->add_node("hp_xp_mp", {
370  { "hp",{
371  { "label", markup::tag("small", markup::span_color(unit::hp_color_max(), markup::bold(_("HP: ")), type.hitpoints()), " | ") },
372  { "use_markup", "true" },
373  { "tooltip", get_hp_tooltip(type.movement_type().get_resistances().damage_table(), [&type](const std::string& dt, bool is_attacker) { return type.resistance_against(dt, is_attacker); }) }
374  } },
375  { "xp",{
376  { "label", markup::tag("small", markup::span_color(unit::xp_color(100, type.can_advance(), true), markup::bold(_("XP: ")), type.experience_needed()), " | ") },
377  { "use_markup", "true" },
378  { "tooltip", (formatter() << _("Experience Modifier: ") << unit_experience_accelerator::get_acceleration() << '%').str() }
379  } },
380  { "mp",{
381  { "label", markup::tag("small", markup::bold(_("MP: ")) + std::to_string(type.movement())) },
382  { "use_markup", "true" },
383  { "tooltip", get_mp_tooltip(type.movement(), [&type](t_translation::terrain_code terrain) { return type.movement_type().movement_cost(terrain); }) }
384  } },
385  });
386 
387  // Print trait details
388  {
389  tree_view_node* header_node = nullptr;
390 
391  for(const auto& tr : type.possible_traits()) {
392  t_string name = tr[type.genders().front() == unit_race::FEMALE ? "female_name" : "male_name"];
393  if(tr["availability"] != "musthave" || name.empty()) {
394  continue;
395  }
396 
397  if(header_node == nullptr) {
398  header_node = &add_name_tree_node(tree_details_->get_root_node(), "header", markup::bold(_("Traits")));
399  }
400 
401  add_name_tree_node(*header_node, "item", name);
402  }
403  }
404 
405  // Print ability details
406  if(!type.abilities_metadata().empty()) {
407 
408  auto& header_node = add_name_tree_node(tree_details_->get_root_node(), "header", markup::bold(_("Abilities")));
409 
410  for(const auto& ab : type.abilities_metadata()) {
411  if(!ab.name.empty()) {
413  header_node,
414  "item",
415  ab.name,
416  markup::span_size("x-large", ab.name) + "\n" + ab.description
417  );
418  }
419  }
420  }
421 
422  print_attack_details(type.attacks(), type.max_attacks(), type.max_attacks(), tree_details_->get_root_node());
423  }
424 }
425 
426 void unit_preview_pane::set_display_data(const unit& u)
427 {
428  // Sets the current type id for the profile button callback to use
429  current_type_ = u.type();
430 
431  if(icon_type_) {
432  std::string mods = u.image_mods();
433 
434  if(u.can_recruit()) {
435  mods += "~BLIT(" + unit::leader_crown() + ")";
436  }
437 
438  for(const std::string& overlay : u.overlays()) {
439  mods += "~BLIT(" + overlay + ")";
440  }
441 
442  mods += image_mods_;
443 
444  icon_type_->set_label(u.absolute_image() + mods);
445  }
446 
447  if(label_name_) {
448  std::string name;
449  if(!u.name().empty()) {
450  name = markup::span_size("large", u.name() + "\n") + markup::tag("small", markup::span_color(font::unit_type_color, u.type_name()));
451  } else {
452  name = markup::span_size("large", u.type_name()) + "\n";
453  }
454 
455  label_name_->set_label(name);
456  label_name_->set_use_markup(true);
457  }
458 
459  if(label_level_) {
460  std::string l_str = VGETTEXT("Lvl $lvl", {{"lvl", std::to_string(u.level())}});
461 
462  label_level_->set_label(markup::bold(l_str));
463  label_level_->set_tooltip(unit_helper::unit_level_tooltip(u));
464  label_level_->set_use_markup(true);
465  }
466 
467  if(label_race_) {
468  label_race_->set_label(u.race()->name(u.gender()));
469  }
470 
471  if(icon_race_) {
472  icon_race_->set_label(u.race()->get_icon_path_stem() + "_30.png");
473  }
474 
475  if(icon_alignment_) {
476  const std::string& alignment_name = unit_alignments::get_string(u.alignment());
477 
478  icon_alignment_->set_label("icons/alignments/alignment_" + alignment_name + "_30.png");
479  icon_alignment_->set_tooltip(unit_type::alignment_description(
480  u.alignment(),
481  u.gender()));
482  }
483 
484  if(label_details_) {
485  std::stringstream str;
486 
487  const std::string name = markup::span_size("large", (!u.name().empty() ? u.name() : " "));
488  str << name << "\n";
489 
491 
492  std::string l_str = VGETTEXT("Lvl $lvl", {{"lvl", std::to_string(u.level())}});
493  str << l_str << "\n";
494 
495  str << unit_type::alignment_description(u.alignment(), u.gender()) << "\n";
496 
497  str << utils::join(u.trait_names(), ", ") << "\n";
498 
499  str << markup::span_color(u.hp_color(), _("HP: "), u.hitpoints(), "/", u.max_hitpoints(), "\n");
500 
501  if(u.can_advance()) {
502  str << markup::span_color(u.xp_color(), _("XP: "), u.experience(), "/", u.max_experience());
503  } else {
504  str << markup::span_color(u.xp_color(), _("XP: "), font::unicode_en_dash);
505  }
506 
507  label_details_->set_label(str.str());
508  label_details_->set_use_markup(true);
509  }
510 
511  if(tree_details_) {
512  tree_details_->clear();
513  const std::string unit_xp = u.can_advance() ? (formatter() << u.experience() << "/" << u.max_experience()).str() : font::unicode_en_dash;
514  tree_details_->add_node("hp_xp_mp", {
515  { "hp",{
516  { "label", markup::tag("small", markup::span_color(u.hp_color(), markup::bold(_("HP: ")), u.hitpoints(), "/", u.max_hitpoints(), " | ")) },
517  { "use_markup", "true" },
518  { "tooltip", get_hp_tooltip(u.get_base_resistances(), [&u](const std::string& dt, bool is_attacker) { return u.resistance_against(dt, is_attacker, u.get_location()); }) }
519  } },
520  { "xp",{
521  { "label", markup::tag("small", markup::span_color(u.xp_color(), markup::bold(_("XP: ")), unit_xp, " | ")) },
522  { "use_markup", "true" },
523  { "tooltip", (formatter() << _("Experience Modifier: ") << unit_experience_accelerator::get_acceleration() << '%').str() }
524  } },
525  { "mp",{
526  { "label", markup::tag("small", markup::bold(_("MP: ")), u.movement_left(), "/", u.total_movement()) },
527  { "use_markup", "true" },
528  { "tooltip", get_mp_tooltip(u.total_movement(), [&u](t_translation::terrain_code terrain) { return u.movement_cost(terrain); }) }
529  } },
530  });
531 
532  if(!u.trait_names().empty()) {
533  auto& header_node = add_name_tree_node(tree_details_->get_root_node(), "header", markup::bold(_("Traits")));
534 
535  assert(u.trait_names().size() == u.trait_descriptions().size());
536  for (std::size_t i = 0; i < u.trait_names().size(); ++i) {
538  header_node,
539  "item",
540  u.trait_names()[i],
541  u.trait_descriptions()[i]
542  );
543  }
544  }
545 
546  if(!u.get_ability_list().empty()) {
547  auto& header_node = add_name_tree_node(tree_details_->get_root_node(), "header", markup::bold(_("Abilities")));
548 
549  for(const auto& ab : u.ability_tooltips()) {
551  header_node,
552  "item",
553  std::get<2>(ab),
554  std::get<3>(ab)
555  );
556  }
557  }
558  print_attack_details(u.attacks(), u.attacks_left(), u.type().max_attacks(), tree_details_->get_root_node());
559  }
560 }
561 
562 void unit_preview_pane::profile_button_callback()
563 {
564  if(get_window() && current_type_) {
565  help::show_unit_description(*current_type_);
566  }
567 }
568 
569 void unit_preview_pane::set_image_mods(const std::string& mods)
570 {
571  image_mods_ = mods;
572 }
573 
574 void unit_preview_pane::set_active(const bool /*active*/)
575 {
576  /* DO NOTHING */
577 }
578 
579 bool unit_preview_pane::get_active() const
580 {
581  return true;
582 }
583 
584 unsigned unit_preview_pane::get_state() const
585 {
586  return ENABLED;
587 }
588 
589 void unit_preview_pane::set_self_active(const bool /*active*/)
590 {
591  /* DO NOTHING */
592 }
593 
594 // }---------- DEFINITION ---------{
595 
596 unit_preview_pane_definition::unit_preview_pane_definition(const config& cfg)
598 {
599  DBG_GUI_P << "Parsing unit preview pane " << id;
600 
601  load_resolutions<resolution>(cfg);
602 }
603 
606 {
607  state.emplace_back(VALIDATE_WML_CHILD(cfg, "background", missing_mandatory_wml_tag("unit_preview_pane_definition][resolution", "background")));
608  state.emplace_back(VALIDATE_WML_CHILD(cfg, "foreground", missing_mandatory_wml_tag("unit_preview_pane_definition][resolution", "foreground")));
609 
610  auto child = VALIDATE_WML_CHILD(cfg, "grid", missing_mandatory_wml_tag("unit_preview_pane_definition][resolution", "grid"));
611  grid = std::make_shared<builder_grid>(child);
612 }
613 
614 // }---------- BUILDER -----------{
615 
616 namespace implementation
617 {
618 
619 builder_unit_preview_pane::builder_unit_preview_pane(const config& cfg)
621  , image_mods(cfg["image_mods"])
622 {
623 }
624 
625 std::unique_ptr<widget> builder_unit_preview_pane::build() const
626 {
627  auto widget = std::make_unique<unit_preview_pane>(*this);
628 
629  DBG_GUI_G << "Window builder: placed unit preview pane '" << id
630  << "' with definition '" << definition << "'.";
631 
632  const auto conf = widget->cast_config_to<unit_preview_pane_definition>();
633  assert(conf);
634 
635  widget->init_grid(*conf->grid);
636  widget->finalize_setup();
637 
638  return widget;
639 }
640 
641 } // namespace implementation
642 
643 // }------------ END --------------
644 
645 } // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
std::ostringstream wrapper.
Definition: formatter.hpp:40
A generic container base class.
At the moment two kinds of tips are known:
Definition: tooltip.cpp:41
Base container class.
Definition: grid.hpp:32
void set_tooltip(const t_string &tooltip)
tree_view_node & add_child(const std::string &id, const widget_data &data, const int index=-1)
Constructs a new child node.
void profile_button_callback()
Callback for the profile button.
static const std::string & type()
Static type getter that does not rely on the widget being constructed.
styled_widget * label_details_
void print_attack_details(T attacks, const int attacks_left, const int max_attacks, tree_view_node &parent_node)
void finalize_setup()
Initializes the internal sub-widget pointers.
Base class for all widgets.
Definition: widget.hpp:55
T * find_widget(const std::string_view id, const bool must_be_active, const bool must_exist)
Gets a widget with the wanted id.
Definition: widget.hpp:747
static prefs & get()
bool empty() const
Definition: tstring.hpp:197
static std::string get_side_color_id(unsigned side)
Definition: team.cpp:956
std::string get_icon_path_stem() const
Gets this race's icon path without state/size suffix and extension.
Definition: race.cpp:163
const t_string & name(GENDER gender=MALE) const
Definition: race.hpp:37
@ FEMALE
Definition: race.hpp:28
A single unit type that the player may recruit.
Definition: types.hpp:43
static std::string alignment_description(unit_alignments::type align, unit_race::GENDER gender=unit_race::MALE)
Implementation detail of unit_type::alignment_description.
Definition: types.cpp:796
int max_attacks() const
Definition: types.hpp:174
This class represents a single unit of a specific type.
Definition: unit.hpp:132
static const std::string & leader_crown()
The path to the leader crown overlay.
Definition: unit.cpp:1177
const config * cfg
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
#define VNGETTEXT(msgid, msgid_plural, count,...)
std::size_t i
Definition: function.cpp:1032
static std::string _(const char *str)
Definition: gettext.hpp:97
std::vector< std::tuple< std::string, t_string, t_string, t_string > > ability_tooltips() const
Gets the names and descriptions of this unit's abilities.
Definition: abilities.cpp:358
std::vector< std::string > get_ability_list() const
Get a list of all abilities by ID.
Definition: abilities.cpp:302
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:520
unit_alignments::type alignment() const
The alignment of this unit.
Definition: unit.hpp:490
int level() const
The current level of this unit.
Definition: unit.hpp:574
const t_string & type_name() const
Gets the translatable name of this unit's type.
Definition: unit.hpp:368
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:514
const unit_race * race() const
Gets this unit's race.
Definition: unit.hpp:508
const unit_type & type() const
This unit's type, accounting for gender and variation.
Definition: unit.hpp:354
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:538
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition: unit.hpp:627
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:544
unit_race::GENDER gender() const
The gender of this unit.
Definition: unit.hpp:480
const t_string & name() const
Gets this unit's translatable display name.
Definition: unit.hpp:402
bool can_advance() const
Checks whether this unit has any options to advance to.
Definition: unit.hpp:271
attack_itors attacks()
Gets an iterator over this unit's attacks.
Definition: unit.hpp:941
utils::string_map_res get_base_resistances() const
Gets resistances without any abilities applied.
Definition: unit.hpp:1072
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition: unit.hpp:1008
color_t xp_color() const
Color for this unit's XP.
Definition: unit.cpp:1252
color_t hp_color() const
Color for this unit's current hitpoints.
Definition: unit.cpp:1208
static color_t hp_color_max()
Definition: unit.cpp:1218
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
Definition: unit.cpp:2769
const std::vector< std::string > & overlays() const
Get the unit's overlay images.
Definition: unit.hpp:1704
std::string absolute_image() const
The name of the file to game_display (used in menus).
Definition: unit.cpp:2588
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1356
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1340
const std::vector< t_string > & trait_descriptions() const
Gets the descriptions of the currently registered traits.
Definition: unit.hpp:1116
const std::vector< t_string > & trait_names() const
Gets the names of the currently registered traits.
Definition: unit.hpp:1106
#define DBG_GUI_G
Definition: log.hpp:41
#define DBG_GUI_P
Definition: log.hpp:66
std::string tooltip
Shown when hovering over an entry in the filter's drop-down list.
Definition: manager.cpp:203
auto string_table
Definition: language.hpp:68
CURSOR_TYPE get()
Definition: cursor.cpp:218
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:189
const std::string weapon_details_sep
Definition: constants.cpp:50
const color_t unit_type_color
const std::string unicode_bullet
Definition: constants.cpp:47
const color_t weapon_details_color
const std::string unicode_en_dash
Definition: constants.cpp:43
const std::string unicode_figure_dash
Definition: constants.cpp:45
const std::string weapon_numbers_sep
Definition: constants.cpp:49
color_t red_to_green(double val, bool for_text)
Return a color corresponding to the value val red for val=0.0 to green for val=100....
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:163
Generic file dialog.
static tree_view_node & add_name_tree_node(tree_view_node &header_node, const std::string &type, const t_string &label, const t_string &tooltip="")
static std::string get_mp_tooltip(int total_movement, const std::function< int(t_translation::terrain_code)> &get)
static std::string get_hp_tooltip(const utils::string_map_res &res, const std::function< int(const std::string &, bool)> &get)
std::shared_ptr< terrain_type_data > load_terrain_types_data()
Load the appropriate terrain types data to use.
Definition: help_impl.cpp:1444
void show_unit_description(const unit &u)
Definition: help.cpp:96
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
Definition: picture.cpp:840
Contains the implementation details for lexical_cast and shouldn't be used directly.
logger & info()
Definition: log.cpp:351
std::string bold(Args &&... data)
Applies bold Pango markup to the input.
Definition: markup.hpp:161
std::string span_color(const color_t &color, Args &&... data)
Applies Pango markup to the input specifying its display color.
Definition: markup.hpp:110
std::string tag(std::string_view tag, Args &&... data)
Wraps the given data in the specified tag.
Definition: markup.hpp:45
std::string span_size(std::string_view size, Args &&... data)
Applies Pango markup to the input specifying its display size.
Definition: markup.hpp:146
play_controller * controller
Definition: resources.cpp:21
const terrain_code VOID_TERRAIN
VOID_TERRAIN is used for shrouded hexes.
bool terrain_matches(const terrain_code &src, const terrain_code &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
const ter_match ALL_OFF_MAP
const terrain_code FOGGED
std::string dgettext(const char *domain, const char *msgid)
Definition: gettext.cpp:425
static std::string unit_level_tooltip(const int level, const std::vector< std::string > &adv_to_types, const std::vector< config > &adv_to_mods)
Definition: helper.cpp:60
std::string resistance_color(const int resistance)
Maps resistance <= -60 (resistance value <= -60%) to intense red.
Definition: helper.cpp:54
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
std::map< std::string, t_string, res_compare > string_map_res
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::string signed_percent(int val)
Convert into a percentage (using the Unicode "−" and +0% convention.
SDL_Window * get_window()
Definition: video.cpp:684
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
static config unit_xp(const unit *u)
Definition: reports.cpp:527
std::string definition
Parameters for the styled_widget.
virtual std::unique_ptr< widget > build() const override
std::vector< state_definition > state
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49
static int get_acceleration()
Definition: types.cpp:529
std::string missing_mandatory_wml_tag(const std::string &section, const std::string &tag)
Returns a standard message for a missing wml child (tag).
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE_WML_CHILD(cfg, key, message)