45 #include <boost/format.hpp>
49 #ifdef __cpp_lib_format
54 const std::string &
tooltip,
const std::string &
help =
"")
57 element[
"text"] = text;
59 if (!
help.empty()) element[
"help"] =
help;
63 const std::string &
tooltip,
const std::string &
help =
"")
66 element[
"image"] =
image;
68 if (!
help.empty()) element[
"help"] =
help;
72 const std::string &
tooltip =
"",
const std::string &
help =
"")
80 const std::string &
tooltip =
"",
const std::string &
help =
"")
90 const std::string&
path,
char const *desc1,
char const *desc2)
97 static std::string
flush(std::ostringstream &
s)
99 std::string r(
s.str());
100 s.str(std::string());
110 }
else if (viewing_team.
fogged(hex)) {
129 #define REPORT_GENERATOR(n, cn) \
130 static config report_##n(const reports::context& cn); \
131 static report_generator_helper reg_gen_##n(#n, &report_##n); \
132 static config report_##n(const reports::context& cn)
174 std::ostringstream str,
tooltip;
200 tooltip <<
"\n\n" <<
_(
"Special Notes:") <<
'\n';
201 for(
const auto& note : notes) {
222 std::ostringstream str,
tooltip;
243 return VGETTEXT(
"Side: <b>$side_name</b> ($color_name)",
256 std::string new_rgb = u_team.
color();
257 std::string mods =
"~RC(" + old_rgb +
">" + new_rgb +
")";
261 std::stringstream text;
262 text <<
" " << u->
side();
301 typedef std::pair<std::string, std::string> pair_string;
302 for (
const pair_string &ps : u->
amla_icons()) {
312 const std::vector<t_string> &traits = u->
trait_names();
315 unsigned nb = traits.size();
316 for (
unsigned i = 0;
i < nb; ++
i)
318 std::ostringstream str,
tooltip;
320 if (
i != nb - 1 ) str <<
", ";
345 N_(
"This unit is invisible. It cannot be seen or attacked by enemy units."));
349 N_(
"This unit has been slowed. It will only deal half its normal damage when attacking and its movement cost is doubled."));
353 N_(
"This unit is poisoned. It will lose 8 HP every turn until it can seek a cure to the poison in a village or from a friendly unit with the ‘cures’ ability.\n\nUnits cannot be killed by poison alone. The poison will not reduce it below 1 HP."));
357 N_(
"This unit has been petrified. It may not move or attack."));
360 add_status(res,
"misc/unhealable.png",
N_(
"unhealable:"),
361 N_(
"This unit is unhealable. It cannot be healed by healers or villages and doesn’t benefit from resting."));
364 add_status(res,
"misc/invulnerable.png",
N_(
"invulnerable:"),
365 N_(
"This unit is invulnerable. It cannot be harmed by any attack."));
383 std::ostringstream str,
tooltip;
403 const map_location& mouseover_hex = rc.screen().mouseover_hex();
404 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
405 const map_location& hex = mouseover_hex.
valid() ? mouseover_hex : displayed_unit_hex;
422 boost::dynamic_bitset<> active;
425 const std::size_t abilities_size = abilities.size();
426 for(std::size_t
i = 0;
i != abilities_size; ++
i) {
428 const auto& [display_name, description, help_id] = abilities[
i];
430 std::ostringstream str,
tooltip;
438 if(
i + 1 != abilities_size) {
447 tooltip <<
'\n' << description;
457 const team &viewing_team = rc.screen().viewing_team();
458 const map_location& mouseover_hex = rc.screen().mouseover_hex();
459 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
460 const map_location& hex = (mouseover_hex.
valid() && !viewing_team.
shrouded(mouseover_hex)) ? mouseover_hex : displayed_unit_hex;
468 const map_location& mouseover_hex = rc.screen().mouseover_hex();
470 const team &viewing_team = rc.screen().viewing_team();
472 if (visible_unit && u && visible_unit->
id() != u->
id() && mouseover_hex.
valid() && !viewing_team.
shrouded(mouseover_hex))
482 std::ostringstream str,
tooltip;
485 std::vector<std::string> resistances_table;
487 bool att_def_diff =
false;
491 std::ostringstream
line;
497 if (res_att == res_def) {
505 resistances_table.push_back(
line.str());
508 tooltip <<
_(
"Resistances:") <<
" ";
512 for (
const std::string &
line : resistances_table) {
531 std::ostringstream str,
tooltip;
539 tooltip <<
_(
"Experience Modifier:") <<
" " << exp_mod <<
'%';
579 std::ostringstream str,
tooltip;
592 if (underlyings.size() != 1 || underlyings.front() != terrain.
number())
606 << (revert ?
_(
"maximum^max.") :
_(
"minimum^min.")) <<
'\n';
618 const team &viewing_team = rc.screen().viewing_team();
619 const map_location& mouseover_hex = rc.screen().mouseover_hex();
620 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
621 const map_location& hex = (mouseover_hex.
valid() && !viewing_team.
shrouded(mouseover_hex)) ? mouseover_hex : displayed_unit_hex;
628 if(attack_indicator_src.
valid())
631 const map_location& mouseover_hex = rc.screen().mouseover_hex();
633 if(visible_unit && u && visible_unit->
id() != u->
id() && mouseover_hex.
valid())
643 std::ostringstream str,
tooltip;
646 str <<
_(
"vision^V:") <<
' ' << u->
vision();
666 std::ostringstream str,
tooltip;
669 str <<
_(
"jamming^J:") <<
' ' << u->
jamming();
683 std::ostringstream str,
tooltip;
684 double movement_frac = 1.0;
686 std::set<terrain_movement> terrain_moves;
690 if (movement_frac > 1.0)
694 tooltip <<
_(
"Movement Costs:") <<
"\n";
701 if (
info.union_type().size() == 1 &&
info.union_type()[0] ==
info.number() &&
info.is_nonnull()) {
711 double movement_red_to_green = 100.0 - 25.0 * tm.moves;
713 std::stringstream temp_str;
718 }
else if (cannot_move) {
719 temp_str <<
"(" << tm.moves <<
")";
721 temp_str << tm.moves;
724 const int movement_hexes_per_turn = u->
total_movement() / tm.moves;
726 for (
int i = 0;
i < movement_hexes_per_turn; ++
i) {
728 temp_str <<
"\u2b23\u200b";
738 int grey = 128 +
static_cast<int>((255 - 128) * movement_frac);
741 if(is_visible_unit) {
743 if(route.
steps.size() > 0) {
752 const auto& end = route.
marks.find(route.
steps.back());
753 if(end != route.
marks.end() && end->second.capture) {
790 std::ostringstream str,
tooltip;
794 struct string_with_tooltip {
801 int base_damage =
at.damage();
802 double specials_damage =
at.modified_damage();
803 int damage_multiplier = 100;
807 damage_multiplier += tod_bonus;
809 if (leader_bonus != 0)
810 damage_multiplier += leader_bonus;
813 int damage_divisor =
slowed ? 20000 : 10000;
815 damage =
round_damage(specials_damage, damage_multiplier * 100, damage_divisor);
819 unsigned cur_hp = std::min<unsigned>(std::max(0, u.
hitpoints()), max_hp);
821 unsigned base_attacks =
at.num_attacks();
822 unsigned min_attacks, max_attacks;
823 at.modified_attacks(min_attacks, max_attacks);
824 unsigned num_attacks =
swarm_blows(min_attacks, max_attacks, cur_hp, max_hp);
827 if (damage > std::round(specials_damage)) {
829 }
else if (damage < std::round(specials_damage)) {
839 if ( tod_bonus || leader_bonus ||
slowed || specials_damage != base_damage )
841 tooltip <<
'\t' <<
_(
"Base damage:") <<
" " << base_damage <<
'\n';
842 if ( specials_damage != base_damage ) {
843 tooltip <<
'\t' <<
_(
"With specials:") <<
" " << specials_damage <<
'\n';
846 tooltip <<
'\t' <<
_(
"Time of day:") <<
" "
850 tooltip <<
'\t' <<
_(
"Leadership:") <<
" "
854 tooltip <<
'\t' <<
_(
"Slowed:") <<
" " <<
"/ 2" <<
'\n';
859 if ( max_attacks != min_attacks && cur_hp != max_hp ) {
860 if ( max_attacks < min_attacks ) {
862 tooltip <<
'\t' <<
_(
"Max swarm bonus:") <<
" " << (min_attacks-max_attacks) <<
'\n';
863 tooltip <<
'\t' <<
_(
"Swarm:") <<
" " <<
"* "<< (100 - cur_hp*100/max_hp) <<
"%\n";
864 tooltip <<
'\t' <<
_(
"Base attacks:") <<
" " <<
'+' << base_attacks <<
'\n';
868 if ( max_attacks != base_attacks ) {
869 int attack_diff =
static_cast<int>(max_attacks) -
static_cast<int>(base_attacks);
875 tooltip <<
'\t' <<
_(
"Base attacks:") <<
" " << base_attacks <<
'\n';
876 if ( max_attacks != base_attacks ) {
877 tooltip <<
'\t' <<
_(
"With specials:") <<
" " << max_attacks <<
'\n';
879 if ( min_attacks != 0 ) {
880 tooltip <<
'\t' <<
_(
"Subject to swarm:") <<
" " << (max_attacks-min_attacks) <<
'\n';
882 tooltip <<
'\t' <<
_(
"Swarm:") <<
" " <<
"* "<< (cur_hp*100/max_hp) <<
"%\n";
885 else if ( num_attacks != base_attacks ) {
886 tooltip <<
'\t' <<
_(
"Base attacks:") <<
" " << base_attacks <<
'\n';
887 tooltip <<
'\t' <<
_(
"With specials:") <<
" " << num_attacks <<
'\n';
893 std::pair<std::string, std::set<std::string>> all_damage_types =
at.damage_types();
894 std::string
type = all_damage_types.first;
895 std::set<std::string> alt_types = all_damage_types.second;
897 for(
auto alt_t : alt_types){
902 const std::string range_png = std::string(
"icons/profiles/") +
at.range() +
"_attack.png~SCALE_INTO(16,16)";
903 const std::string type_png = std::string(
"icons/profiles/") +
type +
".png~SCALE_INTO(16,16)";
904 std::vector<std::string> secondary_types_png;
905 for(
const auto& alt_t : alt_types) {
906 secondary_types_png.push_back(std::string(
"icons/profiles/") + alt_t +
".png~SCALE_INTO(16,16)");
912 for(
const auto& png : secondary_types_png) {
915 if(!all_pngs_exist) {
921 <<
_(
"Damage type:") <<
" " <<
markup::bold(lang_type) <<
"\n"
922 <<
_(
"Damage versus:") <<
" " <<
'\n';
926 std::map<int, std::set<std::string>, std::greater<int>> resistances;
927 std::set<std::string> seen_types;
932 if (
enemy.incapacitated())
938 if (!
enemy.is_visible_to_team(viewing_team, see_all))
940 bool new_type = seen_types.insert(
enemy.type_id()).second;
943 { u.shared_from_this(), hex,
at.shared_from_this() },
944 {
enemy.shared_from_this(),
loc,
nullptr },
946 const auto [damage_type, resistance] = weapon->effective_damage_type();
947 resistances[resistance].insert(
enemy.type_name());
951 for (
const auto& resist : resistances) {
952 int damage_with_resistance =
round_damage(specials_damage, damage_multiplier * resist.first, damage_divisor);
965 const std::string attack_icon =
at.icon() +
"~SCALE_INTO_SHARP(60,60)~CROP(2,2,56,56)~SCALE_INTO_SHARP(32,32)";
971 const std::string spacer =
"misc/blank.png~CROP(0, 0, 16, 21)";
972 add_image(res, spacer +
"~BLIT(" + range_png +
",0,5)", damage_versus.tooltip);
973 add_image(res, spacer +
"~BLIT(" + type_png +
",0,5)", damage_versus.tooltip);
974 for(
auto sec_exist : secondary_types_png){
976 add_image(res, spacer +
"~BLIT(" + sec_exist +
",0,5)", damage_versus.tooltip);
979 add_text(res, damage_and_num_attacks.str, damage_and_num_attacks.tooltip);
980 add_text(res, damage_versus.str, damage_versus.tooltip);
999 if(
at.attacks_used() > 1)
1001 const std::string& attacks_used =
VNGETTEXT(
1003 "uses $num attacks",
1005 { {
"num", std::to_string(at.attacks_used())} }
1009 const std::string& attacks_used_tooltip =
VNGETTEXT(
1010 "This attack uses $num attack point",
1011 "This attack uses $num attack points",
1013 { {
"num", std::to_string(at.attacks_used())} }
1018 const std::string &accuracy_parry =
at.accuracy_parry_description();
1019 if (!accuracy_parry.empty())
1029 { u.shared_from_this(), hex,
at.shared_from_this() },
1030 { sec_u ? sec_u->shared_from_this() :
nullptr, sec_u ? sec_u->get_location() :
map_location(), sec_u_weapon },
1035 boost::dynamic_bitset<> active;
1036 auto specials = ctx.special_tooltips(
at, active);
1037 const std::size_t specials_size = specials.size();
1038 for ( std::size_t
i = 0;
i != specials_size; ++
i )
1041 const auto& name = specials[
i].name;
1042 const auto& description = specials[
i].description;
1043 const color_t &details_color =
1046 str <<
span_color(details_color,
" ",
" ", name) <<
'\n';
1047 std::string help_page =
"weaponspecial_" + specials[
i].help_topic_id;
1052 tooltip <<
'\n' << description;
1057 if(!specials.empty()) {
1062 const std::string spacer =
"misc/blank.png~CROP(0, 0, 1, 5)";
1072 { u.shared_from_this(), hex,
at.shared_from_this() },
1073 { sec_u ? sec_u->shared_from_this() :
nullptr, sec_u ? sec_u->get_location() :
map_location(), sec_u_weapon },
1076 boost::dynamic_bitset<> active;
1078 const std::size_t specials_size = specials.size();
1079 for ( std::size_t
i = 0;
i != specials_size; ++
i )
1082 const auto& [name, description, help_topic_id] = specials[
i];
1083 const color_t& details_color =
1086 str <<
span_color(details_color,
" ",
" ", name) <<
'\n';
1087 const std::string help_page =
"weaponspecial_" + help_topic_id;
1092 tooltip <<
'\n' << description;
1097 if(!specials.empty()) {
1102 const std::string spacer =
"misc/blank.png~CROP(0, 0, 1, 5)";
1115 }
else if(prob < 0.0005) {
1118 std::ostringstream res;
1119 res << std::setprecision(prob < 0.01 ? 1 : prob < 0.1 ? 2 : 3) << 100.0 * prob <<
"%";
1125 std::ostringstream res;
1126 res <<
' ' << std::setw(3) << hp;
1132 if (!attacker || !defender)
return config();
1134 const unit* u = show_attacker ? attacker.get() : defender;
1135 const unit* sec_u = !show_attacker ? attacker.get() : defender;
1138 std::ostringstream str,
tooltip;
1141 std::vector<battle_context> weapons;
1142 for (
unsigned i = 0;
i < attacker->attacks().
size();
i++) {
1144 if (attacker->attacks()[
i].attack_weight() > 0) {
1145 weapons.emplace_back(rc.
units(), attacker_pos, defender->
get_location(),
i, -1, 0.0,
nullptr, attacker);
1152 combatant attacker_combatant(weapon.get_attacker_stats());
1153 combatant defender_combatant(weapon.get_defender_stats());
1154 attacker_combatant.
fight(defender_combatant);
1157 show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
1159 !show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
1161 int total_damage = 0;
1162 int base_damage = 0;
1164 int chance_to_hit = 0;
1165 t_string weapon_name =
_(
"weapon^None");
1168 if (context_unit_stats.
weapon) {
1169 base_damage =
attack_info(rc, *context_unit_stats.
weapon, res, *u, unit_loc, sec_u, other_context_unit_stats.
weapon);
1170 total_damage = context_unit_stats.
damage;
1171 num_blows = context_unit_stats.
num_blows;
1173 weapon_name = context_unit_stats.
weapon->name();
1175 if ( total_damage > base_damage ) {
1177 }
else if ( total_damage < base_damage ) {
1189 str <<
" " <<
span_color(dmg_color, total_damage)
1198 std::vector<std::pair<int, double>> hp_prob_vector;
1201 std::vector<std::pair<double, int>> prob_hp_vector;
1203 combatant*
c = show_attacker ? &attacker_combatant : &defender_combatant;
1206 for (
double prob :
c->hp_dist) {
1209 prob_hp_vector.emplace_back(prob,
i);
1214 std::sort(prob_hp_vector.begin(), prob_hp_vector.end());
1217 std::size_t max_hp_distrib_rows_ = 10;
1220 std::size_t nb_elem = std::min<std::size_t>(max_hp_distrib_rows_, prob_hp_vector.size());
1222 for(std::size_t
i = prob_hp_vector.size() - nb_elem;
i <prob_hp_vector.size();
i++) {
1223 hp_prob_vector.emplace_back(prob_hp_vector[
i].second, prob_hp_vector[
i].first);
1227 std::sort(hp_prob_vector.begin(), hp_prob_vector.end());
1229 std::reverse(hp_prob_vector.begin(), hp_prob_vector.end());
1231 for (
const auto& [hp, prob] : hp_prob_vector) {
1252 if ((u !=
nullptr) && (!u->
attacks().empty())) {
1253 const std::string attack_headline =
_n(
"Attack",
"Attacks", u->
attacks().size());
1260 const std::string
line =
VGETTEXT(
"Remaining: $left/$max",
1261 {{
"left", std::to_string(left)},
1262 {
"max", std::to_string(max)}});
1264 _(
"This unit can attack multiple times per turn."));
1277 const map_location& mouseover_hex = rc.screen().mouseover_hex();
1278 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
1279 const map_location& hex = mouseover_hex.
valid() ? mouseover_hex : displayed_unit_hex;
1289 if (!u)
return report_unit_weapons(rc);
1290 if (!sec_u || u.get() == sec_u)
return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1292 map_location highlighted_hex = rc.screen().displayed_unit_hex();
1295 attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1297 if (!attack_loc.
valid())
1298 return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1309 if (!sec_u || u.get() == sec_u)
return unit_weapons(rc, u.get(), u->get_location());
1311 map_location highlighted_hex = rc.screen().displayed_unit_hex();
1314 attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1316 if (!attack_loc.
valid())
1351 std::ostringstream text;
1354 const std::vector<time_of_day>& schedule = rc.
tod().
times(tod_schedule_hex);
1356 tooltip <<
_(
"Time of day schedule:") <<
" \n";
1368 int times = schedule.size();
1369 text << current + 1 <<
"/" << times;
1375 map_location mouseover_hex = rc.screen().mouseover_hex();
1396 std::string lawful_color(
"white");
1397 std::string chaotic_color(
"white");
1398 std::string liminal_color(
"white");
1401 lawful_color = (
b > 0) ?
"#0f0" :
"#f00";
1402 chaotic_color = (
b < 0) ?
"#0f0" :
"#f00";
1405 liminal_color = (l > 0) ?
"#0f0" :
"#f00";
1408 <<
_(
"Lawful units:") <<
" "
1411 <<
_(
"Chaotic units:") <<
" "
1413 <<
_(
"Liminal units:") <<
" "
1416 std::string tod_image = tod.
image;
1427 map_location mouseover_hex = rc.screen().mouseover_hex();
1450 std::string lawful_color(
"white");
1451 std::string chaotic_color(
"white");
1452 std::string liminal_color(
"white");
1455 lawful_color = (bonus > 0) ?
"green" :
"red";
1456 chaotic_color = (bonus < 0) ?
"green" :
"red";
1458 if (bonus_lim != 0) {
1459 liminal_color = (bonus_lim > 0) ?
"green" :
"red";
1462 <<
_(
"Lawful units:") <<
" "
1465 <<
_(
"Chaotic units:") <<
" "
1467 <<
_(
"Liminal units:") <<
" "
1470 std::string local_tod_image =
"themes/classic/" + local_tod.
image;
1471 std::string global_tod_image =
"themes/classic/" + global_tod.
image;
1473 local_tod_image +=
"~BLIT(";
1479 local_tod_image +=
")";
1491 std::string bg_terrain_image;
1495 bg_terrain_image =
"~BLIT(unit_env/terrain/terrain-" + terrain_id +
".png)" + bg_terrain_image;
1498 std::stringstream color;
1499 color << local_tod.
color;
1501 bg_terrain_image = bg_terrain_image +
"~CS(" + color.str() +
")";
1504 std::string unit_image;
1509 std::string tod_image = global_tod_image +
"~BLIT(" + local_tod_image +
")";
1511 return image_report(tod_image + bg_terrain_image + unit_image,
tooltip.str(),
"time_of_day");
1515 map_location mouseover_hex = rc.screen().mouseover_hex();
1522 std::ostringstream str,
tooltip;
1523 str << rc.tod().turn();
1524 int nb = rc.tod().number_of_turns();
1529 tooltip <<
"\n\n" <<
_(
"When the game exceeds the number of turns indicated by the second number, it will end.");
1536 std::ostringstream str;
1537 const team& viewing_team = rc.screen().viewing_team();
1539 int fake_gold = viewing_team.
gold();
1541 fake_gold -= rc.wb()->get_spent_gold_for(viewing_team.
side());
1544 if (!rc.screen().viewing_team_is_playing()) {
1546 }
else if (fake_gold < 0) {
1552 return text_report(str.str(),
_(
"Gold") +
"\n\n" +
_(
"The amount of gold currently available to recruit and maintain your army."));
1557 std::ostringstream str;
1558 const team &viewing_team = rc.screen().viewing_team();
1559 str << viewing_team.
villages().size() <<
'/';
1561 int unshrouded_villages = 0;
1564 ++unshrouded_villages;
1566 str << unshrouded_villages;
1568 str << rc.map().villages().size();
1570 return gray_inactive(rc,str.str(),
_(
"Villages") +
"\n\n" +
_(
"The fraction of known villages that your side has captured."));
1575 return gray_inactive(rc, std::to_string(rc.dc().side_units(rc.screen().viewing_team().side())),
_(
"Units") +
"\n\n" +
_(
"The total number of units on your side."));
1580 std::ostringstream str;
1581 const team& viewing_team = rc.screen().viewing_team();
1584 return gray_inactive(rc,str.str(),
_(
"Upkeep") +
"\n\n" +
_(
"The expenses incurred at the end of every turn to maintain your army. The first number is the amount of gold that will be deducted. It is equal to the number of unit levels not supported by villages. The second is the total cost of upkeep, including that covered by villages — in other words, the amount of gold that would be deducted if you lost all villages."));
1589 const team& viewing_team = rc.screen().viewing_team();
1596 std::ostringstream str;
1597 const team& viewing_team = rc.screen().viewing_team();
1600 if (!rc.screen().viewing_team_is_playing()) {
1614 return text_report(str.str(),
_(
"Net Income") +
"\n\n" +
_(
"The net amount of gold you gain or lose each turn, taking into account income from controlled villages and payment of upkeep."));
1618 void blit_tced_icon(
config &
cfg,
const std::string &terrain_id,
const std::string &icon_image,
bool high_res,
1619 const std::string &terrain_name) {
1620 const std::string tc_base = high_res ?
"images/buttons/icon-base-32.png" :
"images/buttons/icon-base-16.png";
1621 const std::string terrain_image =
"terrain/" + icon_image + (high_res ?
"_30.png" :
".png");
1622 add_image(
cfg, tc_base +
"~RC(magenta>" + terrain_id +
")~BLIT(" + terrain_image +
")", terrain_name);
1628 const gamemap& map = rc.map();
1629 map_location mouseover_hex = rc.screen().mouseover_hex();
1632 mouseover_hex = rc.screen().selected_hex();
1646 bool high_res =
false;
1667 if(terrain_icon.empty()) {
1670 blit_tced_icon(
cfg, terrain_id, terrain_icon, high_res, terrain_name);
1674 int owner = rc.dc().village_owner(mouseover_hex);
1678 const team& viewing_team = rc.screen().viewing_team();
1680 if(!viewing_team.
fogged(mouseover_hex)) {
1681 const team& owner_team = rc.dc().get_team(owner);
1686 std::string mods =
"~RC(" + old_rgb +
">" + new_rgb +
")";
1691 std::string side = std::to_string(owner_team.
side());
1704 const gamemap &map = rc.map();
1705 const team& viewing_team = rc.screen().viewing_team();
1706 map_location mouseover_hex = rc.screen().mouseover_hex();
1714 std::ostringstream str;
1717 int owner = rc.dc().village_owner(mouseover_hex);
1718 if (owner == 0 || viewing_team.
fogged(mouseover_hex)) {
1720 }
else if (owner == viewing_team.
side()) {
1722 }
else if (viewing_team.
is_enemy(owner)) {
1729 if(!underlying_desc.empty()) {
1730 str << underlying_desc;
1741 std::ostringstream text;
1743 std::ostringstream
help;
1745 text << static_cast<int>(rc.screen().get_zoom_factor() * 100) <<
"%";
1752 const gamemap &map = rc.map();
1753 map_location mouseover_hex = rc.screen().mouseover_hex(),
1754 displayed_unit_hex = rc.screen().displayed_unit_hex(),
1757 if (!map.
on_board(mouseover_hex)) {
1769 std::ostringstream str;
1770 str << mouseover_hex;
1773 const team &viewing_team = rc.screen().viewing_team();
1775 (displayed_unit_hex != mouseover_hex
1776 && displayed_unit_hex != rc.screen().selected_hex())
1777 || viewing_team.
shrouded(mouseover_hex))
1785 str <<
" " << defense <<
"%," << move_cost;
1786 }
else if (mouseover_hex == displayed_unit_hex) {
1787 str <<
" " << defense <<
"%,‒";
1796 const team &active_team = rc.screen().playing_team();
1800 std::string mods =
"~RC(" + old_rgb +
">" + new_rgb +
")";
1809 const std::set<std::string> &observers = rc.screen().observers();
1810 if (observers.empty())
1813 std::ostringstream str;
1814 str <<
_(
"Observers:") <<
'\n';
1815 for (
const std::string &obs : observers) {
1830 const auto now = std::chrono::system_clock::now();
1849 using namespace std::chrono_literals;
1850 const team& viewing_team = rc.screen().viewing_team();
1852 return report_report_clock(rc);
1855 std::ostringstream time_str, formatted_time_str;
1857 using std::chrono::duration_cast;
1858 #ifdef __cpp_lib_format
1859 auto sec = duration_cast<std::chrono::seconds>(viewing_team.
countdown_time());
1862 auto fmt = [](
const auto& duration) -> std::string {
1863 return formatter{} << std::setw(2) << std::setfill(
'0') << duration.count();
1867 auto sec = duration_cast<std::chrono::seconds>(viewing_team.
countdown_time());
1868 auto min = duration_cast<std::chrono::minutes>(sec);
1869 time_str << fmt(min) <<
':' << fmt(sec - min);
1873 if (!rc.screen().viewing_team_is_playing()) {
1875 }
else if (sec < 60
s) {
1876 formatted_time_str <<
span_color(
"#c80000", time_str.str());
1877 }
else if (sec < 120
s) {
1878 formatted_time_str <<
span_color(
"#c8c800", time_str.str());
1880 formatted_time_str << time_str.str();
1885 add_text(report, formatted_time_str.str(),
1886 _(
"Turn Countdown") +
"\n\n" +
_(
"Countdown until your turn automatically ends."));
1904 return iter->second->generate(rc);
1914 return std::invoke(iter->second, rc);
int generic_combat_modifier(int lawful_bonus, unit_alignments::type alignment, bool is_fearless, int max_liminal_bonus)
Returns the amount that a unit's damage should be multiplied by due to a given lawful_bonus.
int combat_modifier(const unit_map &units, const gamemap &map, const map_location &loc, unit_alignments::type alignment, bool is_fearless)
Returns the amount that a unit's damage should be multiplied by due to the current time of day.
int under_leadership(const unit &u, const map_location &loc)
Tests if the unit at loc is currently affected by leadership.
Various functions that implement attacks and attack calculations.
unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp, unsigned max_hp)
Calculates the number of blows resulting from swarm.
Computes the statistics of a battle between an attacker and a defender unit.
A config object defines a single node in a WML file, with access to child nodes.
config & add_child(std::string_view key)
const team & get_team(int side) const
This getter takes a 1-based side number, not a 0-based team number.
const unit * get_visible_unit(const map_location &loc, const team ¤t_team, bool see_all=false) const
unit_const_ptr get_visible_unit_shared_ptr(const map_location &loc, const team ¤t_team, bool see_all=false) const
const team & viewing_team() const
const team & playing_team() const
virtual const map_location & displayed_unit_hex() const
Virtual functions shadowed in game_display.
const map_location & selected_hex() const
bool show_everything() const
static display * get_singleton()
Returns the display object if a display object exists.
bool viewing_team_is_playing() const
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
const map_location & get_attack_indicator_src()
const pathfind::marked_route & get_route()
Gets the route along which footsteps are drawn to show movement of a unit.
static game_display * get_singleton()
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Encapsulates the map of the game.
bool is_village(const map_location &loc) const
std::string get_underlying_terrain_string(const map_location &loc) const
std::string get_terrain_string(const map_location &loc) const
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
bool use_twelve_hour_clock_format()
const display_context & dc() const
const unit_map & units() const
const tod_manager & tod() const
const gamemap & map() const
const display & screen() const
void register_generator(const std::string &name, generator *)
std::set< std::string > all_reports_
config generate_builtin_report(const std::string &name, const context &rc)
Generate the specified report using the given context, excluding dynamic generators.
const std::set< std::string > & report_list()
std::function< config(const reports::context &)> generator_function
config generate_report(const std::string &name, const context &ct)
Generate the specified report using the given context.
dynamic_report_generators dynamic_generators_
void set_for_listing(bool for_listing)
std::vector< unit_ability_t::tooltip_info > abilities_special_tooltips(const attack_type &at, boost::dynamic_bitset<> &active_list) const
static specials_context_t make(specials_combatant &&self, specials_combatant &&other, bool attacking)
const std::string & str() const
This class stores all the data for a single 'side' (in game nomenclature).
const std::string & color() const
const std::string & side_name() const
bool is_enemy(int n) const
const std::set< map_location > & villages() const
static t_string get_side_color_name_for_UI(unsigned side)
static std::string get_side_color_id(unsigned side)
bool shrouded(const map_location &loc) const
std::chrono::milliseconds countdown_time() const
const std::string & flag_icon() const
bool fogged(const map_location &loc) const
const t_string & income_description_enemy() const
const std::string & icon_image() const
const t_string & income_description() const
const t_string & income_description_ally() const
const std::string & id() const
const t_string & description() const
const t_translation::ter_list & def_type() const
const t_translation::ter_list & union_type() const
const t_string & income_description_own() const
t_translation::terrain_code number() const
int get_max_liminal_bonus() const
const std::vector< time_of_day > & times() const
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
time_of_day get_illuminated_time_of_day(const unit_map &units, const gamemap &map, const map_location &loc, int for_turn=0) const
Returns time of day object for the passed turn at a location.
int get_current_time() const
const std::string & id() const
const t_string & name(GENDER gender=MALE) const
A single unit type that the player may recruit.
static std::string alignment_description(unit_alignments::type align, unit_race::GENDER gender=unit_race::MALE)
Implementation detail of unit_type::alignment_description.
bool show_variations_in_help() const
Whether the unit type has at least one help-visible variation.
This class represents a single unit of a specific type.
@ selected_hex
Image on the selected unit.
static std::string _n(const char *str1, const char *str2, int n)
static std::string _(const char *str)
bool invisible(const map_location &loc, bool see_all=true) const
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.
unit_alignments::type alignment() const
The alignment of this unit.
int level() const
The current level of this unit.
const t_string & type_name() const
Gets the translatable name 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.
const std::string & type_id() const
The id of this unit's type.
const unit_race * race() const
Gets this unit's race.
const unit_type & type() const
This unit's type, accounting for gender and variation.
int experience() const
The current number of experience points this unit has.
const std::string & id() const
Gets this unit's id.
int side() const
The side this unit belongs to.
std::vector< t_string > unit_special_notes() const
The unit's special notes.
int max_experience() const
The max number of experience points this unit can have.
unit_race::GENDER gender() const
The gender of this unit.
const t_string & name() const
Gets this unit's translatable display name.
t_string unit_description() const
A detailed description of this unit.
@ 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_UNHEALABLE
The unit has not moved.
@ STATE_POISONED
The unit is slowed - it moves slower and does less damage.
std::vector< std::pair< std::string, std::string > > amla_icons() const
Gets the image and description data for modification advancements.
bool can_advance() const
Checks whether this unit has any options to advance to.
std::map< std::string, std::string > advancement_icons() const
Gets and image path and and associated description for each advancement option.
int resistance_against(const std::string &damage_name, bool attacker, const map_location &loc) const
The unit's resistance against a given damage type.
attack_itors attacks()
Gets an iterator over this unit's attacks.
int defense_modifier(const t_translation::terrain_code &terrain, const map_location &loc) const
The unit's defense on a given terrain.
utils::string_map_res get_base_resistances() const
Gets resistances without any abilities applied.
int max_attacks() const
The maximum number of attacks this unit may perform per turn, usually 1.
int attacks_left() const
Gets the remaining number of attacks this unit can perform 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 image_mods() const
Gets an IPF string containing all IPF image mods.
std::string absolute_image() const
The name of the file to game_display (used in menus).
int jamming() const
Gets the unit's jamming points.
const map_location & get_location() const
The current map location this unit is at.
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit's movement cost on a particular terrain.
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.
int vision() const
Gets the unit's vision points.
std::vector< std::string > trait_nonhidden_ids() const
Gets the ids of the traits corresponding to those returned by trait_names() and trait_descriptions().
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
const std::vector< t_string > & trait_descriptions() const
Gets the descriptions of the currently registered traits.
const std::vector< t_string > & trait_names() const
Gets the names of the currently registered traits.
std::string tooltip
Shown when hovering over an entry in the filter's drop-down list.
constexpr int round_damage(double base_damage, int bonus, int divisor)
round (base_damage * bonus / divisor) to the closest integer, but up or down towards base_damage
auto format_local_timestamp(const std::chrono::system_clock::time_point &time, std::string_view format="%F %T")
double get_battery_percentage()
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
const std::string weapon_details_sep
std::string escape_text(std::string_view text)
Escapes the pango markup characters in a text.
const std::string unicode_bullet
const color_t weapon_details_color
const color_t good_dmg_color
const std::string unicode_en_dash
const color_t weapon_color
const std::string unicode_figure_dash
const color_t INACTIVE_COLOR
const std::string weapon_numbers_sep
const std::string unicode_minus
const color_t bad_dmg_color
color_t blue_to_white(double val, bool for_text)
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....
std::string get_unit_type_help_id(const unit_type &t)
Given a unit type, find the corresponding help topic's id.
Functions to load and save images from/to disk.
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
std::string italic(Args &&... data)
Applies italic Pango markup to the input.
std::string bold(Args &&... data)
Applies bold Pango markup to the input.
std::string span_color(const color_t &color, Args &&... data)
Applies Pango markup to the input specifying its display color.
std::string tag(std::string_view tag, Args &&... data)
Wraps the given data in the specified tag.
std::string help_to_pango_markup(const std::string &help_markup)
static std::string at(const std::string &file, int line)
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)
static std::string unit_level_tooltip(const int level, const std::vector< std::string > &adv_to_types, const std::vector< config > &adv_to_mods)
std::string resistance_color(const int resistance)
Maps resistance <= -60 (resistance value <= -60%) to intense red.
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::string signed_value(int val)
Convert into a signed value (using the Unicode "−" and +0 convention.
std::string signed_percent(int val)
Convert into a percentage (using the Unicode "−" and +0% convention.
@ enemy
Belongs to a non-friendly side; normally visualised by not displaying an orb.
This module contains various pathfinding functions and utilities.
std::shared_ptr< const unit > unit_const_ptr
std::shared_ptr< const attack_type > const_attack_ptr
static config unit_name(const unit *u)
static config image_report(const std::string &image, const std::string &tooltip="", const std::string &help="")
static std::string flush(std::ostringstream &s)
static void add_image(config &report, const std::string &image, const std::string &tooltip, const std::string &help="")
static config unit_hp(const reports::context &rc, const unit *u)
static config unit_type(const unit *u)
static std::string side_tooltip(const team &team)
static config unit_jamming(const unit *u)
static const unit * get_visible_unit(const reports::context &rc)
static config tod_stats_at(const reports::context &rc, const map_location &hex)
static unit_const_ptr get_selected_unit_ptr(const reports::context &rc)
static int attack_info(const reports::context &rc, const attack_type &at, config &res, const unit &u, const map_location &hex, const unit *sec_u=nullptr, const const_attack_ptr &sec_u_weapon=nullptr)
std::map< std::string, reports::generator_function > static_report_generators
static config unit_side(const reports::context &rc, const unit *u)
static config unit_defense(const reports::context &rc, const unit *u, const map_location &displayed_unit_hex)
static std::string format_prob(double prob)
static config unit_status(const reports::context &rc, const unit *u)
static config gray_inactive(const reports::context &rc, const std::string &str, const std::string &tooltip="")
static static_report_generators static_generators
static config unit_level(const unit *u)
static config unit_vision(const unit *u)
static const color_t attack_info_percent_color(int resistance)
Maps resistance <= -60 (resistance value <= -60%) to intense red.
static config unit_traits(const unit *u)
static config unit_abilities_report(const unit *u, const map_location &loc)
static config unit_box_at(const reports::context &rc, const map_location &mouseover_hex)
static const time_of_day get_visible_time_of_day_at(const reports::context &rc, const map_location &hex)
static config unit_race(const unit *u)
static void add_text(config &report, const std::string &text, const std::string &tooltip, const std::string &help="")
static config time_of_day_at(const reports::context &rc, const map_location &mouseover_hex)
static config unit_weapons(const reports::context &rc, const unit_const_ptr &attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
#define REPORT_GENERATOR(n, cn)
static config text_report(const std::string &text, const std::string &tooltip="", const std::string &help="")
static config unit_moves(const reports::context &rc, const unit *u, bool is_visible_unit)
static config unit_alignment(const reports::context &rc, const unit *u, const map_location &hex)
static void add_status(config &r, const std::string &path, char const *desc1, char const *desc2)
static const unit * get_selected_unit(const reports::context &rc)
static std::string format_hp(unsigned hp)
static config unit_advancement_options(const unit *u)
static config unit_xp(const unit *u)
Structure describing the statistics of a unit involved in the battle.
unsigned int num_blows
Effective number of blows, takes swarm into account.
const_attack_ptr weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
int damage
Effective damage of the weapon (all factors accounted for).
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
The basic class for representing 8-bit RGB or RGBA colour values.
void fight(combatant &opponent, bool levelup_considered=true)
Simulate a fight! Can be called multiple times for cumulative calculations.
Encapsulates the map of the game.
static const map_location & null_location()
Structure which holds a single route and marks for special events.
std::vector< map_location > & steps
report_generator_helper(const char *name, const reports::generator_function &g)
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Object which defines a time of day with associated bonuses, image, sounds etc.
tod_color color
The color modifications that should be made to the game board to reflect the time of day.
int lawful_bonus
The % bonus lawful units receive.
std::string image
The image to be displayed in the game status.
static int get_acceleration()
static map_location::direction s