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