help topic generator: cleanup, move special notes to separate function

This commit is contained in:
Subhraman Sarkar 2025-03-03 09:57:05 +05:30
parent 68e4c64e71
commit cf0eb00518

View File

@ -59,14 +59,16 @@ struct terrain_movement_info
}
};
static std::string best_str(bool best) {
namespace {
std::string best_str(bool best) {
std::string lang_policy = (best ? _("Best of") : _("Worst of"));
std::string color_policy = (best ? "green": "red");
return markup::span_color(color_policy, lang_policy);
}
static std::string format_mp_entry(const int cost, const int max_cost) {
std::string format_mp_entry(const int cost, const int max_cost) {
std::stringstream str_unformatted;
const bool cannot = cost < max_cost;
@ -96,7 +98,7 @@ static std::string format_mp_entry(const int cost, const int max_cost) {
typedef t_translation::ter_list::const_iterator ter_iter;
// Gets an english description of a terrain ter_list alias behavior: "Best of cave, hills", "Worst of Swamp, Forest" etc.
static std::string print_behavior_description(
std::string print_behavior_description(
const ter_iter& start,
const ter_iter& end,
const std::shared_ptr<terrain_type_data>& tdata,
@ -140,12 +142,7 @@ static std::string print_behavior_description(
ss << best_str(best) << " ";
if (!first_level) ss << "( ";
ss << names.at(0);
for (std::size_t i = 1; i < names.size(); i++) {
ss << ", " << names.at(i);
}
ss << utils::join(names, ", ");
if (!first_level) ss << " )";
} else {
std::vector<std::string> names;
@ -163,7 +160,7 @@ static std::string print_behavior_description(
if (!first_level) ss << "( ";
ss << print_behavior_description(start, *last_change_pos-1, tdata, false, begin_best);
// Printed the (parenthesized) leading part from before the change, now print the remaining names in this group.
for (const std::string & s : names) {
for (const std::string& s : names) {
ss << ", " << s;
}
if (!first_level) ss << " )";
@ -171,6 +168,39 @@ static std::string print_behavior_description(
return ss.str();
}
std::vector<std::string> get_special_notes(const terrain_type& type) {
// Special notes are generated from the terrain's properties - at the moment there's no way for WML authors
// to add their own via a [special_note] tag.
std::vector<std::string> special_notes;
if(type.is_village()) {
special_notes.push_back(_("Villages allow any unit stationed therein to heal, or to be cured of poison."));
} else if(type.gives_healing() > 0) {
auto symbols = utils::string_map{{"amount", std::to_string(type.gives_healing())}};
// TRANSLATORS: special note for terrains such as the oasis; the only terrain in core with this property heals 8 hp just like a village.
// For the single-hitpoint variant, the wording is different because I assume the player will be more interested in the curing-poison part than the minimal healing.
auto message = VNGETTEXT("This terrain allows units to be cured of poison, or to heal a single hitpoint.",
"This terrain allows units to heal $amount hitpoints, or to be cured of poison, as if stationed in a village.",
type.gives_healing(), symbols);
special_notes.push_back(std::move(message));
}
if(type.is_castle()) {
special_notes.push_back(_("This terrain is a castle — units can be recruited onto it from a connected keep."));
}
if(type.is_keep() && type.is_castle()) {
// TRANSLATORS: The "this terrain is a castle" note will also be shown directly above this one.
special_notes.push_back(_("This terrain is a keep — a leader can recruit from this hex onto connected castle hexes."));
} else if(type.is_keep() && !type.is_castle()) {
// TRANSLATORS: Special note for a terrain, but none of the terrains in mainline do this.
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."));
}
return special_notes;
}
}
std::string terrain_topic_generator::operator()() const {
std::stringstream ss;
@ -200,45 +230,21 @@ std::string terrain_topic_generator::operator()() const {
ss << "Base terrain: ";
const auto base_t = tdata->get_terrain_info(
t_translation::terrain_code(type_.number().base, t_translation::NO_LAYER));
ss << markup::make_link(base_t.editor_name(), terrain_prefix + base_t.id());
ss << markup::make_link(base_t.editor_name(),
(base_t.hide_help() ? "." : "") + terrain_prefix + base_t.id());
ss << ", ";
ss << "Overlay terrain: ";
const auto overlay_t = tdata->get_terrain_info(
t_translation::terrain_code(t_translation::NO_LAYER, type_.number().overlay));
ss << markup::make_link(overlay_t.editor_name(), (overlay_t.hide_help() ? "." : "") + terrain_prefix + overlay_t.id());
ss << markup::make_link(overlay_t.editor_name(),
(overlay_t.hide_help() ? "." : "") + terrain_prefix + overlay_t.id());
ss << "\n";
}
// Special notes are generated from the terrain's properties - at the moment there's no way for WML authors
// to add their own via a [special_note] tag.
std::vector<std::string> special_notes;
if(type_.is_village()) {
special_notes.push_back(_("Villages allow any unit stationed therein to heal, or to be cured of poison."));
} else if(type_.gives_healing() > 0) {
auto symbols = utils::string_map{{"amount", std::to_string(type_.gives_healing())}};
// TRANSLATORS: special note for terrains such as the oasis; the only terrain in core with this property heals 8 hp just like a village.
// For the single-hitpoint variant, the wording is different because I assume the player will be more interested in the curing-poison part than the minimal healing.
auto message = VNGETTEXT("This terrain allows units to be cured of poison, or to heal a single hitpoint.",
"This terrain allows units to heal $amount hitpoints, or to be cured of poison, as if stationed in a village.",
type_.gives_healing(), symbols);
special_notes.push_back(std::move(message));
}
if(type_.is_castle()) {
special_notes.push_back(_("This terrain is a castle — units can be recruited onto it from a connected keep."));
}
if(type_.is_keep() && type_.is_castle()) {
// TRANSLATORS: The "this terrain is a castle" note will also be shown directly above this one.
special_notes.push_back(_("This terrain is a keep — a leader can recruit from this hex onto connected castle hexes."));
} else if(type_.is_keep() && !type_.is_castle()) {
// TRANSLATORS: Special note for a terrain, but none of the terrains in mainline do this.
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."));
}
if(!special_notes.empty()) {
const auto& notes = get_special_notes(type_);
if(!notes.empty()) {
ss << "\n\n" << markup::tag("header", _("Special Notes")) << "\n\n";
for(const auto& note : special_notes) {
for(const auto& note : notes) {
ss << font::unicode_bullet << " " << note << '\n';
}
}
@ -306,21 +312,20 @@ std::string terrain_topic_generator::operator()() const {
ss << type_.income_description();
if (type_.editor_image().empty()) { // Note: this is purely temporary to help make a different help entry
ss << "\nEditor Image: Empty\n";
} else {
ss << "\nEditor Image: " << type_.editor_image() << "\n";
}
ss << "\nEditor Image: ";
// Note: this is purely temporary to help make a different help entry
ss << (type_.editor_image().empty() ? "Empty" : type_.editor_image());
ss << "\n";
const t_translation::ter_list& underlying_mvt_terrains = tdata->underlying_mvt_terrain(type_.number());
ss << "\nDebug Mvt Description String:";
for (const t_translation::terrain_code & t : underlying_mvt_terrains) {
for (const t_translation::terrain_code& t : underlying_mvt_terrains) {
ss << " " << t;
}
const t_translation::ter_list& underlying_def_terrains = tdata->underlying_def_terrain(type_.number());
ss << "\nDebug Def Description String:";
for (const t_translation::terrain_code & t : underlying_def_terrains) {
for (const t_translation::terrain_code& t : underlying_def_terrains) {
ss << " " << t;
}