16 #define GETTEXT_DOMAIN "wesnoth-help"
41 #define WRN_HP LOG_STREAM(warn, log_help)
42 #define DBG_HP LOG_STREAM(debug, log_help)
63 std::string lang_policy = (best ?
_(
"Best of") :
_(
"Worst of"));
64 std::string color_policy = (best ?
"green":
"red");
66 return "<span color='" + color_policy +
"'>" + lang_policy +
"</span>";
69 typedef t_translation::ter_list::const_iterator
ter_iter;
74 if (
start == end)
return "";
77 utils::optional<ter_iter> last_change_pos;
79 bool best = begin_best;
89 if (!last_change_pos) {
90 std::vector<std::string>
names;
94 names.push_back(
_(
"base terrain"));
102 if (
names.empty())
return "";
106 if (!first_level) ss <<
"( ";
109 for (std::size_t
i = 1;
i <
names.size();
i++) {
110 ss <<
", " <<
names.at(
i);
113 if (!first_level) ss <<
" )";
115 std::vector<std::string>
names;
116 for (
ter_iter i = *last_change_pos+1;
i != end; ++
i) {
127 if (!first_level) ss <<
"( ";
130 for (
const std::string &
s :
names) {
133 if (!first_level) ss <<
" )";
139 std::stringstream ss;
142 ss <<
"<img>src='images/buttons/icon-base-32.png~RC(magenta>" <<
type_.
id()
143 <<
")~BLIT("<<
"terrain/" <<
type_.
icon_image() <<
"_30.png)" <<
"'</img>";
156 WRN_HP <<
"When building terrain help topics, we couldn't acquire any terrain types data";
162 std::vector<std::string> special_notes;
165 special_notes.push_back(
_(
"Villages allow any unit stationed therein to heal, or to be cured of poison."));
170 auto message =
VNGETTEXT(
"This terrain allows units to be cured of poison, or to heal a single hitpoint.",
171 "This terrain allows units to heal $amount hitpoints, or to be cured of poison, as if stationed in a village.",
173 special_notes.push_back(std::move(message));
177 special_notes.push_back(
_(
"This terrain is a castle — units can be recruited onto it from a connected keep."));
181 special_notes.push_back(
_(
"This terrain is a keep — a leader can recruit from this hex onto connected castle hexes."));
184 special_notes.push_back(
_(
"This unusual keep allows a leader to recruit while standing on it, but does not allow a leader on a connected keep to recruit onto this hex."));
187 if(!special_notes.empty()) {
188 ss <<
"\n\n" <<
_(
"<header>Special Notes</header>") <<
"\n\n";
189 for(
const auto& note : special_notes) {
197 std::vector<t_string> underlying;
199 const terrain_type& base = tdata->get_terrain_info(underlying_terrain);
209 ss <<
"\n" <<
VNGETTEXT(
"Basic terrain type: $types",
"Basic terrain types: $types", underlying.size(), symbols);
221 ss <<
"\n" <<
VGETTEXT(
"Typical base terrain: $type", symbols);
227 ss <<
"\n" <<
_(
"Movement properties: ");
231 ss <<
"\n" <<
_(
"Defense properties: ");
238 ss <<
"ID: " <<
type_.
id() <<
"\n";
243 ss <<
"Keep: " << (
type_.
is_keep() ?
"Yes" :
"No") <<
"\n";
250 ss <<
"Terrain string: " <<
type_.
number() <<
"\n";
260 ss <<
"\nEditor Image: Empty\n";
266 ss <<
"\nDebug Mvt Description String:";
272 ss <<
"\nDebug Def Description String:";
294 for(
i++;
i < l.size();
i++) {
303 std::stringstream ss;
304 std::string clear_stringstream;
314 const std::string &male_portrait = male_type.
small_profile().empty() ?
316 const std::string &female_portrait = female_type.
small_profile().empty() ?
319 const bool has_male_portrait = !male_portrait.empty() && male_portrait != male_type.
image() && male_portrait !=
"unit_image";
320 const bool has_female_portrait = !female_portrait.empty() && female_portrait != male_portrait && female_portrait != female_type.
image() && female_portrait !=
"unit_image";
322 int sz = (has_male_portrait && has_female_portrait ? 300 : 400);
324 sz = (has_male_portrait && has_female_portrait ? 200 : 300);
334 if (has_male_portrait) {
335 ss <<
"<img src='" << male_portrait <<
"~FL(horiz)~SCALE_INTO(" << sz <<
',' << sz <<
")' box='no' align='right' float='yes' />";
338 if (has_female_portrait) {
339 ss <<
"<img src='" << female_portrait <<
"~FL(horiz)~SCALE_INTO(" << sz <<
',' << sz <<
")' box='no' align='right' float='yes' />";
343 ss <<
"<img src='" << male_type.
image();
344 ss <<
"~RC(" << male_type.
flag_rgb() <<
">red)";
345 if (
screen_width >= 1200) { ss <<
"~SCALE_SHARP(200%,200%)"; };
346 ss <<
"' box='no' />";
348 if (female_type.
image() != male_type.
image()) {
349 ss <<
"<img src='" << female_type.
image();
350 ss <<
"~RC(" << female_type.
flag_rgb() <<
">red)";
351 if (
screen_width >= 1200) { ss <<
"~SCALE_SHARP(200%,200%)"; };
352 ss <<
"' box='no' />";
359 const bool first_reverse_value =
true;
360 bool reverse = first_reverse_value;
363 std::vector<std::string> adv_units =
367 for (
const std::string &adv : adv_units) {
375 ss <<
_(
"Advances from: ");
377 ss <<
_(
"Advances to: ");
384 std::string lang_unit =
type->type_name();
387 const std::string section_prefix =
type->show_variations_in_help() ?
".." :
"";
400 }
while(reverse != first_reverse_value);
411 ss <<
_(
"Base units: ");
421 for (
const std::string &var_id : parent->
variations()) {
424 if(
type.hide_help()) {
429 ss <<
_(
"Variations: ");
437 std::string var_name =
type.variation_name();
451 if (race_name.empty()) {
452 race_name =
_ (
"race^Miscellaneous");
455 ss <<
make_link(race_name,
"..race_" + race_id);
461 std::vector<trait_data> must_have_traits;
462 std::vector<trait_data> random_traits;
463 int must_have_nameless_traits = 0;
465 for(
const config& trait : traits) {
466 const std::string& male_name = trait[
"male_name"].str();
467 const std::string& female_name = trait[
"female_name"].str();
468 std::string trait_name;
470 trait_name = male_name;
472 trait_name = female_name;
473 else if (! trait[
"name"].str().empty())
474 trait_name = trait[
"name"].str();
479 if (lang_trait_name.empty() && trait[
"availability"].str() ==
"musthave") {
480 ++must_have_nameless_traits;
483 const std::string ref_id =
"traits_"+trait[
"id"].str();
484 ((trait[
"availability"].str() ==
"musthave") ? must_have_traits : random_traits).emplace_back(lang_trait_name, ref_id);
487 bool line1 = !must_have_traits.empty();
488 bool line2 = !random_traits.empty() &&
type_.
num_traits() > must_have_traits.size();
491 std::string traits_label =
_(
"Traits");
494 std::stringstream must_have_count;
495 must_have_count <<
"\n (" << must_have_traits.size() <<
") : ";
496 std::stringstream random_count;
497 random_count <<
" (" << (
type_.
num_traits() - must_have_traits.size() - must_have_nameless_traits) <<
") : ";
498 ss << must_have_count.str();
500 ss <<
"\n" << random_count.str();
509 ss <<
_(
"Traits") <<
" (" << (
type_.
num_traits() - must_have_nameless_traits) <<
") : ";
519 ss <<
_(
"Abilities: ");
524 const std::string ref_id =
ability_prefix + iter->id + iter->name.base_str();
526 if(iter->name.empty()) {
545 ss <<
_(
"Ability Upgrades: ");
550 const std::string ref_id =
ability_prefix + iter->id + iter->name.base_str();
552 if(iter->name.empty()) {
610 ss <<
"\n" << detailed_description;
613 ss <<
"\n<header>" <<
_(
"Special Notes") <<
"</header>\n";
614 for(
const auto& note : notes) {
620 ss <<
"\n<header>" <<
_(
"Attacks") <<
"</header>";
629 <<
"<col><b>" <<
_(
"Icon") <<
"</b></col>"
630 <<
"<col><b>" <<
_(
"Name") <<
"</b></col>"
631 <<
"<col><b>" <<
_(
"Strikes") <<
"</b></col>"
632 <<
"<col><b>" <<
_(
"Range") <<
"</b></col>"
633 <<
"<col><b>" <<
_(
"Type") <<
"</b></col>"
634 <<
"<col><b>" <<
_(
"Special") <<
"</b></col>"
637 std::stringstream attack_ss;
641 std::string lang_weapon = attack.name();
642 std::string lang_type =
string_table[
"type_" + attack.type()];
644 attack_ss <<
"<row>";
647 attack_ss <<
"<col><img src='" << attack.icon() <<
"'/></col>";
650 attack_ss <<
"<col>" << lang_weapon <<
"</col>";
654 <<
" " << attack.accuracy_parry_description() <<
"</col>";
657 const std::string range_icon =
"icons/profiles/" + attack.range() +
"_attack.png~SCALE_INTO(16,16)";
658 attack_ss <<
"<col>" <<
"<img src='" << range_icon <<
"'/>";
659 if (attack.min_range() > 1 || attack.max_range() > 1) {
660 attack_ss << attack.min_range() <<
"-" << attack.max_range() <<
' ';
662 attack_ss <<
string_table[
"range_" + attack.range()] <<
"</col>";
665 const std::string type_icon =
"icons/profiles/" + attack.type() +
".png~SCALE_INTO(16,16)";
666 attack_ss <<
"<col>" <<
"<img src='" << type_icon <<
"'/>";
667 attack_ss << lang_type <<
"</col>";
670 attack_ss <<
"<col>";
671 std::vector<std::pair<t_string, t_string>> specials = attack.special_tooltips();
672 if (!specials.empty()) {
673 std::string lang_special =
"";
674 const std::size_t specials_size = specials.size();
675 for (std::size_t
i = 0;
i != specials_size; ++
i) {
676 const std::string ref_id = std::string(
"weaponspecial_")
677 + specials[
i].first.base_str();
678 lang_special = (specials[
i].first);
679 attack_ss <<
make_link(lang_special, ref_id);
680 if (
i+1 != specials_size) {
687 attack_ss <<
"</col>";
688 attack_ss <<
"</row>";
691 ss << attack_ss.str();
699 for (
const config &
t : traits) {
700 if (
t[
"availability"].str() ==
"musthave") {
701 for (
const config & effect :
t.child_range(
"effect")) {
702 if (!effect.has_child(
"filter")
704 movement_type.
merge(effect, effect[
"replace"].to_bool());
716 ss <<
"\n<header>" <<
_(
"Resistances") <<
"</header>";
721 ss <<
"<col><b>" <<
_(
"Attack Type") <<
"</b></col>";
722 ss <<
"<col><b>" <<
_(
"Resistance") <<
"</b></col>";
726 for(std::pair<std::string, std::string> dam_it : dam_tab) {
727 int resistance = 100;
729 resistance -= std::stoi(dam_it.second);
730 }
catch(std::invalid_argument&) {}
731 std::string resist = std::to_string(resistance) +
'%';
732 const std::size_t pos = resist.find(
'-');
733 if (pos != std::string::npos) {
737 const std::string lang_type =
string_table[
"type_" + dam_it.first];
738 const std::string type_icon =
"icons/profiles/" + dam_it.first +
".png~SCALE_INTO(16,16)";
740 ss <<
"<col>" <<
"<img src='" << type_icon <<
"'/>" << lang_type <<
"</col>";
741 std::stringstream str;
742 str <<
"<span color='" << color <<
"' text='"<< resist <<
"'/>";
743 ss <<
"<col>" << str.str() <<
"</col>";
751 ss <<
"\n<header>" <<
_(
"Terrain Modifiers") <<
"</header>";
754 ss <<
"<col><b>" <<
_(
"Terrain") <<
"</b></col>";
755 ss <<
"<col><b>" <<
_(
"Defense") <<
"</b></col>";
756 ss <<
"<col><b>" <<
_(
"Movement Cost") <<
"</b></col>";
757 if (has_terrain_defense_caps) { ss <<
"<col><b>" <<
_(
"Defense Cap") <<
"</b></col>"; }
758 if (has_vision) { ss <<
"<col><b>" <<
_(
"Vision Cost") <<
"</b></col>"; }
759 if (has_jamming) { ss <<
"<col><b>" <<
_(
"Jamming Cost") <<
"</b></col>"; }
762 std::set<terrain_movement_info> terrain_moves;
771 if (cannot_move &&
info.hide_if_impassable()) {
775 if (
info.is_indivisible() &&
info.is_nonnull()) {
787 terrain_moves.insert(movement_info);
794 bool high_res =
false;
795 const std::string tc_base = high_res ?
"images/buttons/icon-base-32.png" :
"images/buttons/icon-base-16.png";
796 const std::string terrain_image =
"icons/terrain/terrain_type_" + m.id + (high_res ?
"_30.png" :
".png");
798 const std::string final_image = tc_base +
"~RC(magenta>" + m.id +
")~BLIT(" + terrain_image +
")";
801 ss <<
"<col>" <<
"<img src='" + final_image +
"'/>" +
make_link(m.name,
"..terrain_" + m.id) <<
"</col>";
807 std::stringstream str;
808 std::stringstream str_unformatted;
809 str <<
"<span color='" << color <<
"'>"<< m.defense <<
"%</span>";
810 str_unformatted << m.defense <<
"%";
811 ss <<
"<col>" << str.str() <<
"</col>";
814 str.str(clear_stringstream);
815 str_unformatted.str(clear_stringstream);
817 double movement_red_to_green = 100.0 - 25.0 * m.movement_cost;
821 str <<
"<span color='" << movement_color <<
"'>";
824 if(cannot_move && (m.movement_cost >
type_.
movement() + 5)) {
826 }
else if(cannot_move) {
827 str_unformatted <<
"(" << m.movement_cost <<
")";
829 str_unformatted << m.movement_cost;
831 if(m.movement_cost != 0) {
832 const int movement_hexes_per_turn =
type_.
movement() / m.movement_cost;
833 str_unformatted <<
" ";
834 for(
int i = 0;
i < movement_hexes_per_turn; ++
i) {
836 str_unformatted <<
"\u2b23\u200b";
839 str << str_unformatted.str() <<
"</span>";
840 ss <<
"<col>" << str.str() <<
"</col>";
843 if (has_terrain_defense_caps) {
844 str.str(clear_stringstream);
845 str_unformatted.str(clear_stringstream);
847 str <<
"<span color='"<< color <<
"'>" << m.defense <<
"%</span>";
848 str_unformatted << m.defense <<
"%";
853 ss <<
"<col>" << str.str() <<
"</col>";
858 str.str(clear_stringstream);
859 str_unformatted.str(clear_stringstream);
860 const bool cannot_view = m.vision_cost >
type_.
vision();
861 double vision_red_to_green = 100.0 - 25.0 * m.vision_cost;
865 str <<
"<span color='" << vision_color <<
"'>";
868 if(cannot_view && (m.vision_cost >
type_.
vision() + 5)) {
870 }
else if(cannot_view) {
871 str_unformatted <<
"(" << m.vision_cost <<
")";
873 str_unformatted << m.vision_cost;
875 if(m.vision_cost != 0) {
876 const int vision_hexes_per_turn =
type_.
vision() / m.vision_cost;
877 str_unformatted <<
" ";
878 for(
int i = 0;
i < vision_hexes_per_turn; ++
i) {
880 str_unformatted <<
"\u2b23\u200b";
883 str << str_unformatted.str() <<
"</span>";
884 ss <<
"<col>" << str.str() <<
"</col>";
889 str.str(clear_stringstream);
890 str_unformatted.str(clear_stringstream);
891 const bool cannot_jam = m.jamming_cost >
type_.
jamming();
892 double jamming_red_to_green = 100.0 - 25.0 * m.jamming_cost;
896 str <<
"<span color='" << jamming_color <<
"'>";
899 if (cannot_jam && m.jamming_cost >
type_.
jamming() + 5) {
901 }
else if(cannot_jam) {
902 str_unformatted <<
"(" << m.jamming_cost <<
")";
904 str_unformatted << m.jamming_cost;
906 if(m.jamming_cost != 0) {
907 const int jamming_hexes_per_turn =
type_.
jamming() / m.jamming_cost;
908 str_unformatted <<
" ";
909 for(
int i = 0;
i < jamming_hexes_per_turn; ++
i) {
911 str_unformatted <<
"\u2b23\u200b";
914 str << str_unformatted.str() <<
"</span>";
915 ss <<
"<col>" << str.str() <<
"</col>";
924 WRN_HP <<
"When building unit help topics, the display object was null and we couldn't get the terrain info we need.";
std::vector< std::string > names
A config object defines a single node in a WML file, with access to child nodes.
boost::iterator_range< const_child_iterator > const_child_itors
const terrain_type & type_
virtual std::string operator()() const
virtual std::string operator()() const
void push_header(std::vector< help::item > &row, const std::string &name) const
const std::string variation_
bool capped(const t_translation::terrain_code &terrain) const
Returns whether there is a defense cap associated to this terrain.
The basic "size" of the unit - flying, small land, large land, etc.
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...
bool has_vision_data() const
Returns whether or not there are any vision-specific costs.
bool has_jamming_data() const
Returns whether or not there are any jamming-specific costs.
bool has_terrain_defense_caps(const std::set< t_translation::terrain_code > &ts) const
Returns whether or not there are any terrain caps with respect to a set of terrains.
int defense_modifier(const t_translation::terrain_code &terrain) const
Returns the defensive value of the indicated terrain.
int jamming_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to "jam" through the indicated terrain.
int vision_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to see through the indicated terrain.
int movement_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to move through the indicated terrain.
utils::string_map_res damage_table() const
Returns a map from damage types to resistances.
terrain_defense & get_defense()
const std::string & str() const
const std::string & editor_group() const
bool has_default_base() const
const std::string & icon_image() const
const t_string & income_description() const
bool is_combined() const
True for instances created by the terrain_code(base, overlay) constructor.
const std::string & editor_image() const
bool is_nonnull() const
True if this object represents some sentinel values.
const std::string & id() const
const t_string & help_topic_text() const
const t_translation::ter_list & def_type() const
const t_translation::ter_list & mvt_type() const
The underlying type of the terrain.
int light_bonus(int base) const
Returns the light (lawful) bonus for this terrain when the time of day gives a base bonus.
const t_translation::ter_list & union_type() const
static bool is_indivisible(t_translation::terrain_code id, const t_translation::ter_list &underlying)
Returns true if a terrain has no underlying types other than itself, in respect of either union,...
const t_string & editor_name() const
int gives_healing() const
t_translation::terrain_code default_base() const
Overlay terrains defined by a [terrain_type] can declare a fallback base terrain, for use when the ov...
bool hide_in_editor() const
t_translation::terrain_code number() const
const t_string & plural_name() 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.
void build_unit_type(const unit_type &ut, unit_type::BUILD_STATUS status) const
Makes sure the provided unit_type is built to the specified level.
A single unit type that the player may recruit.
const std::vector< std::string > advances_from() const
A vector of unit_type ids that can advance to this unit_type.
std::string race_id() const
Returns the ID of this type's race without the need to build the type.
static std::string alignment_description(unit_alignments::type align, unit_race::GENDER gender=unit_race::MALE)
Implementation detail of unit_type::alignment_description.
const std::string & image() const
const std::string & id() const
The id for this unit_type.
const std::vector< ability_metadata > & adv_abilities_metadata() const
Some extra abilities that may be gained through AMLA advancements.
const movetype & movement_type() const
bool show_variations_in_help() const
Whether the unit type has at least one help-visible variation.
const unit_race * race() const
Never returns nullptr, but may point to the null race.
const unit_type & get_variation(const std::string &id) const
const_attack_itors attacks() const
const std::vector< std::string > & advances_to() const
A vector of unit_type ids that this unit_type can advance to.
bool has_gender_variation(const unit_race::GENDER gender) const
t_string unit_description() const
const std::vector< unit_race::GENDER > & genders() const
The returned vector will not be empty, provided this has been built to the HELP_INDEXED status.
std::vector< std::string > variations() const
const std::string & flag_rgb() const
std::vector< t_string > special_notes() const
Returns all notes that should be displayed in the help page for this type, including those found in a...
config::const_child_itors modification_advancements() const
Returns two iterators pointing to a range of AMLA configs.
const unit_type & get_gender_unit_type(std::string gender) const
Returns a gendered variant of this unit_type.
int experience_needed(bool with_acceleration=true) const
const std::string & big_profile() 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 std::vector< ability_metadata > & abilities_metadata() const
const config & get_cfg() const
unsigned int num_traits() const
static std::string _(const char *str)
static lg::log_domain log_help("help")
symbol_table string_table
Standard logging facilities (interface).
EXIT_STATUS start(bool clear_id, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
int pango_line_width(const std::string &line, int font_size, font::pango_text::FONT_STYLE font_style=font::pango_text::STYLE_NORMAL)
Determine the width of a line of text given a certain font size.
const std::string unicode_bullet
const std::string unicode_figure_dash
const std::string weapon_numbers_sep
const std::string unicode_minus
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....
unsigned screen_width
The screen resolution and pixel pitch should be available for all widgets since their drawing method ...
std::string bold(const std::string &s)
std::string make_link(const std::string &text, const std::string &dst)
static std::string print_behavior_description(ter_iter start, ter_iter end, const std::shared_ptr< terrain_type_data > &tdata, bool first_level=true, bool begin_best=true)
t_translation::ter_list::const_iterator ter_iter
const std::string unit_prefix
const std::string variation_prefix
UNIT_DESCRIPTION_TYPE description_type(const unit_type &type)
Return the type of description that should be shown for a unit of the given kind.
const std::string ability_prefix
std::pair< std::string, std::string > trait_data
const int normal_font_size
const std::string terrain_prefix
const std::string unknown_unit_topic
std::shared_ptr< terrain_type_data > load_terrain_types_data()
Load the appropriate terrain types data to use.
static std::string best_str(bool best)
static void print_trait_list(std::stringstream &ss, const std::vector< trait_data > &l)
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.
std::vector< terrain_code > ter_list
const ter_match ALL_OFF_MAP
const terrain_code FOGGED
static std::string gettext(const char *str)
int icompare(const std::string &s1, const std::string &s2)
Case-insensitive lexicographical comparison.
std::string resistance_color(const int resistance)
Maps resistance <= -60 (resistance value <= -60%) to intense red.
std::map< std::string, t_string, res_compare > string_map_res
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)
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
int get_pixel_scale()
Get the current active pixel scale multiplier.
Transitional API for porting SDL_ttf-based code to Pango.
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
bool operator<(const terrain_movement_info &other) const
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
static map_location::DIRECTION s
unit_type_data unit_types