45 #include <boost/dynamic_bitset.hpp> 46 #include <boost/format.hpp> 47 #include <boost/lexical_cast.hpp> 50 const std::string &
tooltip,
const std::string &
help =
"")
53 element[
"text"] = text;
54 if (!tooltip.empty()) element[
"tooltip"] = tooltip;
55 if (!
help.empty()) element[
"help"] =
help;
59 const std::string &
tooltip,
const std::string &
help =
"")
62 element[
"image"] = image;
63 if (!tooltip.empty()) element[
"tooltip"] = tooltip;
64 if (!
help.empty()) element[
"help"] =
help;
68 const std::string &
tooltip =
"",
const std::string &
help =
"")
76 const std::string &
tooltip =
"",
const std::string &
help =
"")
86 char const *
path,
char const *desc1,
char const *desc2)
93 static std::string
flush(std::ostringstream &
s)
95 std::string r(s.str());
106 }
else if (viewing_team.
fogged(hex)) {
125 #define REPORT_GENERATOR(n, cn) \ 126 static config report_##n(reports::context & cn); \ 127 static report_generator_helper reg_gen_##n(#n, &report_##n); \ 128 static config report_##n(reports::context & cn) 130 static char const *
naps =
"</span>";
172 std::ostringstream str,
tooltip;
173 str <<
"<b>" << name <<
"</b>";
174 tooltip <<
_(
"Name: ") <<
"<b>" << name <<
"</b>";
193 std::ostringstream str,
tooltip;
195 tooltip <<
_(
"Type: ") <<
"<b>" << u->
type_name() <<
"</b>\n" 198 tooltip <<
"\n\n" <<
_(
"Special Notes:") <<
'\n';
199 for(
const auto& note : notes) {
203 return text_report(str.str(), tooltip.str(), has_variations_prefix +
"unit_" + u->
type_id());
219 std::ostringstream str,
tooltip;
221 tooltip <<
_(
"Race: ") <<
"<b>" << u->
race()->
name(u->
gender()) <<
"</b>";
240 return VGETTEXT(
"Side: <b>$side_name</b> ($color_name)",
253 std::string new_rgb = u_team.
color();
254 std::string mods =
"~RC(" + old_rgb +
">" + new_rgb +
")";
255 if (flag_icon.empty())
258 std::stringstream text;
259 text <<
" " << u->
side();
262 add_image(report, flag_icon + mods, tooltip,
"");
298 typedef std::pair<std::string, std::string> pair_string;
299 for (
const pair_string &ps : u->
amla_icons()) {
309 const std::vector<t_string> &traits = u->
trait_names();
312 unsigned nb = traits.size();
313 for (
unsigned i = 0;
i < nb; ++
i)
315 std::ostringstream str,
tooltip;
317 if (
i != nb - 1 ) str <<
", ";
318 tooltip <<
_(
"Trait: ") <<
"<b>" << traits[
i] <<
"</b>\n" 320 add_text(res, str.str(), tooltip.str(),
"traits_" + trait_ids[
i]);
341 add_status(res,
"misc/invisible.png",
N_(
"invisible: "),
342 N_(
"This unit is invisible. It cannot be seen or attacked by enemy units."));
346 N_(
"This unit has been slowed. It will only deal half its normal damage when attacking and its movement cost is doubled."));
350 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."));
353 add_status(res,
"misc/petrified.png",
N_(
"petrified: "),
354 N_(
"This unit has been petrified. It may not move or attack."));
372 std::ostringstream str,
tooltip;
385 tooltip <<
_(
"Alignment: ") <<
"<b>" << align <<
"</b>\n" 388 return text_report(str.str(), tooltip.str(),
"time_of_day");
393 const map_location& mouseover_hex = rc.screen().mouseover_hex();
394 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
395 const map_location& hex = mouseover_hex.
valid() ? mouseover_hex : displayed_unit_hex;
412 boost::dynamic_bitset<> active;
415 const std::size_t abilities_size = abilities.size();
416 for(std::size_t
i = 0;
i != abilities_size; ++
i) {
418 const auto& [
id,
base_name, display_name, description] = abilities[
i];
420 std::ostringstream str,
tooltip;
428 if(i + 1 != abilities_size) {
432 tooltip <<
_(
"Ability: ") <<
"<b>" << display_name <<
"</b>";
434 tooltip <<
"<i>" <<
_(
" (inactive)") <<
"</i>";
437 tooltip <<
'\n' << description;
439 add_text(res, str.str(), tooltip.str(),
"ability_" +
id + base_name.base_str());
447 const map_location& mouseover_hex = rc.screen().mouseover_hex();
455 const map_location& mouseover_hex = rc.screen().mouseover_hex();
457 if(visible_unit && u && visible_unit->
id() != u->
id() && mouseover_hex.
valid())
467 std::ostringstream str,
tooltip;
471 std::vector<std::string> resistances_table;
473 bool att_def_diff =
false;
477 std::ostringstream
line;
483 if (res_att == res_def) {
494 resistances_table.push_back(line.str());
497 tooltip <<
_(
"Resistances: ");
499 tooltip <<
_(
"(Att / Def)");
501 for (
const std::string &
line : resistances_table) {
520 std::ostringstream str,
tooltip;
530 tooltip <<
_(
"Experience Modifier: ") << exp_mod <<
'%';
570 std::ostringstream str,
tooltip;
583 if (underlyings.size() != 1 || underlyings.front() != terrain)
596 <<
span_color(t_color) << t_def <<
'%' << naps
597 << (revert ?
_(
"maximum^max.") :
_(
"minimum^min.")) <<
'\n';
602 tooltip <<
"<b>" <<
_(
"Defense: ") <<
span_color(color) << def <<
'%' << naps <<
"</b>";
604 return text_report(str.str(), tooltip.str(), has_variations_prefix +
"unit_" + u->
type_id());
609 const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
610 const map_location& mouseover_hex = rc.screen().mouseover_hex();
611 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
612 const map_location& hex = (mouseover_hex.
valid() && !viewing_team.
shrouded(mouseover_hex)) ? mouseover_hex : displayed_unit_hex;
619 if(attack_indicator_src.
valid())
622 const map_location& mouseover_hex = rc.screen().mouseover_hex();
624 if(visible_unit && u && visible_unit->
id() != u->
id() && mouseover_hex.
valid())
635 std::ostringstream str,
tooltip;
637 str <<
_(
"vision:") <<
' ' << u->
vision();
638 tooltip <<
_(
"vision:") <<
' ' << u->
vision() <<
'\n';
641 if (static_cast<std::streamoff>(str.tellp()) == 0)
642 str <<
_(
"jamming:") <<
' ' << u->
jamming();
643 tooltip <<
_(
"jamming:") <<
' ' << u->
jamming() <<
'\n';
661 std::ostringstream str,
tooltip;
662 double movement_frac = 1.0;
664 std::set<terrain_movement> terrain_moves;
668 if (movement_frac > 1.0)
672 tooltip <<
_(
"Movement Costs:") <<
"\n";
685 tooltip << tm.name <<
": ";
689 double movement_red_to_green = 100.0 - 25.0 * tm.moves;
693 tooltip <<
"<span foreground=\"" << color <<
"\">";
698 }
else if (cannot_move) {
699 tooltip <<
"(" << tm.moves <<
")";
704 const int movement_hexes_per_turn = u->
total_movement() / tm.moves;
706 for(
int i = 0;
i < movement_hexes_per_turn; ++
i) {
710 tooltip <<
naps <<
'\n';
713 int grey = 128 +
static_cast<int>((255 - 128) * movement_frac);
716 if(is_visible_unit) {
718 if(route.
steps.size() > 0) {
727 const auto& end = route.
marks.find(route.
steps.back());
728 if(end != route.
marks.end() && end->second.capture) {
765 std::ostringstream str,
tooltip;
768 struct string_with_tooltip {
775 int base_damage = at.
damage();
777 int damage_multiplier = 100;
780 damage_multiplier += tod_bonus;
782 if (leader_bonus != 0)
783 damage_multiplier += leader_bonus;
786 int damage_divisor = slowed ? 20000 : 10000;
788 damage =
round_damage(specials_damage, damage_multiplier * 100, damage_divisor);
792 unsigned cur_hp = std::min<unsigned>(std::max(0, u.
hitpoints()), max_hp);
795 unsigned min_attacks, max_attacks;
797 unsigned num_attacks =
swarm_blows(min_attacks, max_attacks, cur_hp, max_hp);
800 if ( damage > specials_damage )
802 else if ( damage < specials_damage )
808 tooltip <<
_(
"Weapon: ") <<
"<b>" << at.
name() <<
"</b>\n" 809 <<
_(
"Damage: ") <<
"<b>" << damage <<
"</b>\n";
811 if ( tod_bonus || leader_bonus || slowed || specials_damage != base_damage )
813 tooltip <<
'\t' <<
_(
"Base damage: ") << base_damage <<
'\n';
814 if ( specials_damage != base_damage ) {
815 tooltip <<
'\t' <<
_(
"With specials: ") << specials_damage <<
'\n';
818 tooltip <<
'\t' <<
_(
"Time of day: ")
822 tooltip <<
'\t' <<
_(
"Leadership: ")
826 tooltip <<
'\t' <<
_(
"Slowed: ") <<
"/ 2" <<
'\n';
830 tooltip <<
_(
"Attacks: ") <<
"<b>" << num_attacks <<
"</b>\n";
831 if ( max_attacks != min_attacks && cur_hp != max_hp ) {
832 if ( max_attacks < min_attacks ) {
834 tooltip <<
'\t' <<
_(
"Max swarm bonus: ") << (min_attacks-max_attacks) <<
'\n';
835 tooltip <<
'\t' <<
_(
"Swarm: ") <<
"* "<< (100 - cur_hp*100/max_hp) <<
"%\n";
836 tooltip <<
'\t' <<
_(
"Base attacks: ") <<
'+' << base_attacks <<
'\n';
840 if ( max_attacks != base_attacks ) {
841 int attack_diff =
static_cast<int>(max_attacks) - static_cast<int>(base_attacks);
847 tooltip <<
'\t' <<
_(
"Base attacks: ") << base_attacks <<
'\n';
848 if ( max_attacks != base_attacks ) {
849 tooltip <<
'\t' <<
_(
"With specials: ") << max_attacks <<
'\n';
851 if ( min_attacks != 0 ) {
852 tooltip <<
'\t' <<
_(
"Subject to swarm: ") << (max_attacks-min_attacks) <<
'\n';
854 tooltip <<
'\t' <<
_(
"Swarm: ") <<
"* "<< (cur_hp*100/max_hp) <<
"%\n";
857 else if ( num_attacks != base_attacks ) {
858 tooltip <<
'\t' <<
_(
"Base attacks: ") << base_attacks <<
'\n';
859 tooltip <<
'\t' <<
_(
"With specials: ") << num_attacks <<
'\n';
862 const string_with_tooltip damage_and_num_attacks {
flush(str),
flush(tooltip)};
868 const std::string range_png = std::string(
"icons/profiles/") + at.
range() +
"_attack.png~SCALE_INTO(16,16)";
869 const std::string type_png = std::string(
"icons/profiles/") + at.
type() +
".png~SCALE_INTO(16,16)";
873 if(!range_png_exists || !type_png_exists) {
876 << lang_type <<
"</span>\n";
879 tooltip <<
_(
"Weapon range: ") <<
"<b>" << range <<
"</b>\n" 880 <<
_(
"Damage type: ") <<
"<b>" << lang_type <<
"</b>\n" 881 <<
_(
"Damage versus: ") <<
'\n';
885 std::map<int, std::set<std::string>, std::greater<int>> resistances;
886 std::set<std::string> seen_types;
891 if (
enemy.incapacitated())
897 if (!
enemy.is_visible_to_team(viewing_team, see_all))
899 bool new_type = seen_types.insert(
enemy.type_id()).second;
901 int resistance =
enemy.resistance_against(at,
false, loc);
902 resistances[resistance].insert(
enemy.type_name());
906 for (
const auto& resist : resistances) {
907 int damage_with_resistance =
round_damage(specials_damage, damage_multiplier * resist.first, damage_divisor);
908 tooltip <<
"<b>" << damage_with_resistance <<
"</b> " 915 const string_with_tooltip damage_versus {
flush(str),
flush(tooltip)};
921 const std::string attack_icon = at.
icon() +
"~SCALE_INTO_SHARP(60,60)~CROP(2,2,56,56)~SCALE_INTO_SHARP(32,32)";
927 const std::string spacer =
"misc/blank.png~CROP(0, 0, 16, 21)";
928 add_image(res, spacer +
"~BLIT(" + range_png +
",0,5)", damage_versus.tooltip);
929 add_image(res, spacer +
"~BLIT(" + type_png +
",0,5)", damage_versus.tooltip);
930 add_text(res, damage_and_num_attacks.str, damage_and_num_attacks.tooltip);
931 add_text(res, damage_versus.str, damage_versus.tooltip);
934 if (!accuracy_parry.empty())
937 <<
" " << accuracy_parry <<
"</span>\n";
940 tooltip <<
_(
"Accuracy:") <<
"<b>" 943 int parry = at.
parry();
945 tooltip <<
_(
"Parry:") <<
"<b>" 956 at.
specials_context(u.shared_from_this(), sec_u->shared_from_this(), hex, sec_u->get_location(), attacking, sec_u_weapon);
958 boost::dynamic_bitset<> active;
959 const std::vector<std::pair<t_string, t_string>> &specials = at.
special_tooltips(&active);
960 const std::size_t specials_size = specials.size();
961 for ( std::size_t
i = 0;
i != specials_size; ++
i )
964 const t_string &name = specials[
i].first;
965 const t_string &description = specials[
i].second;
969 str <<
span_color(details_color) <<
" " <<
" " << name <<
naps <<
'\n';
970 std::string help_page =
"weaponspecial_" + name.
base_str();
971 tooltip <<
_(
"Weapon special: ") <<
"<b>" << name <<
"</b>";
973 tooltip <<
"<i>" <<
_(
" (inactive)") <<
"</i>";
974 tooltip <<
'\n' << description;
978 if(!specials.empty()) {
983 const std::string spacer =
"misc/blank.png~CROP(0, 0, 1, 5)";
996 }
else if(prob < 0.0005) {
999 std::ostringstream res;
1000 res << std::setprecision(prob < 0.01 ? 1 : prob < 0.1 ? 2 : 3) << 100.0 * prob <<
"%";
1006 std::ostringstream res;
1007 res <<
' ' << std::setw(3) << hp;
1013 if (!attacker || !defender)
return config();
1015 const unit* u = show_attacker ? attacker.get() : defender;
1016 const unit* sec_u = !show_attacker ? attacker.get() : defender;
1019 std::ostringstream str,
tooltip;
1022 std::vector<battle_context> weapons;
1023 for (
unsigned int i = 0;
i < attacker->attacks().size();
i++) {
1025 if (attacker->attacks()[
i].attack_weight() > 0) {
1026 weapons.emplace_back(rc.
units(), attacker_pos, defender->
get_location(),
i, -1, 0.0,
nullptr, attacker);
1033 combatant attacker_combatant(weapon.get_attacker_stats());
1034 combatant defender_combatant(weapon.get_defender_stats());
1035 attacker_combatant.
fight(defender_combatant);
1038 show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
1040 !show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
1042 int total_damage = 0;
1043 int base_damage = 0;
1045 int chance_to_hit = 0;
1046 t_string weapon_name =
_(
"weapon^None");
1049 if (context_unit_stats.
weapon) {
1050 base_damage =
attack_info(rc, *context_unit_stats.
weapon, res, *u, unit_loc, sec_u, other_context_unit_stats.
weapon);
1051 total_damage = context_unit_stats.
damage;
1052 num_blows = context_unit_stats.
num_blows;
1054 weapon_name = context_unit_stats.
weapon->name();
1056 if ( total_damage > base_damage )
1058 else if ( total_damage < base_damage )
1062 tooltip <<
_(
"Weapon: ") <<
"<b>" << weapon_name <<
"</b>\n" 1063 <<
_(
"Damage: ") <<
"<b>" <<
"0" <<
"</b>\n";
1071 <<
" (" <<
span_color(chance_color) << chance_to_hit <<
"%" <<
naps <<
")" 1074 tooltip <<
_(
"Weapon: ") <<
"<b>" << weapon_name <<
"</b>\n" 1075 <<
_(
"Total damage") <<
"<b>" << total_damage <<
"</b>\n";
1078 std::vector<std::pair<int, double>> hp_prob_vector;
1081 std::vector<std::pair<double, int>> prob_hp_vector;
1084 combatant*
c = show_attacker ? &attacker_combatant : &defender_combatant;
1086 for(i = 0; i < static_cast<int>(c->
hp_dist.size()); i++) {
1091 prob_hp_vector.emplace_back(prob, i);
1094 std::sort(prob_hp_vector.begin(), prob_hp_vector.end());
1097 int max_hp_distrib_rows_ = 10;
1100 int nb_elem = std::min<int>(max_hp_distrib_rows_, prob_hp_vector.size());
1102 for(i = prob_hp_vector.size() - nb_elem;
1103 i < static_cast<int>(prob_hp_vector.size()); i++) {
1105 hp_prob_vector.emplace_back(prob_hp_vector[i].second, prob_hp_vector[i].first);
1109 std::sort(hp_prob_vector.begin(), hp_prob_vector.end());
1111 std::reverse(hp_prob_vector.begin(), hp_prob_vector.end());
1113 for(i = 0; i < static_cast<int>(hp_prob_vector.size()); i++) {
1115 int hp = hp_prob_vector[
i].first;
1116 double prob = hp_prob_vector[
i].second;
1138 if ((u !=
nullptr) && (!u->
attacks().empty())) {
1139 const std::string attack_headline =
_n(
"Attack",
"Attacks", u->
attacks().size());
1142 + attack_headline +
"</span>" +
'\n',
"");
1147 const std::string
line =
VGETTEXT(
"Remaining: $left/$max",
1148 {{
"left", std::to_string(left)},
1149 {
"max", std::to_string(max)}});
1151 _(
"This unit can attack multiple times per turn."));
1164 const map_location& mouseover_hex = rc.screen().mouseover_hex();
1165 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
1166 const map_location& hex = mouseover_hex.
valid() ? mouseover_hex : displayed_unit_hex;
1176 if (!u)
return report_unit_weapons(rc);
1177 if (!sec_u || u.get() == sec_u)
return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1179 map_location highlighted_hex = rc.screen().displayed_unit_hex();
1182 attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1184 if (!attack_loc.
valid())
1185 return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1196 if (!sec_u || u.get() == sec_u)
return unit_weapons(rc, u.get(), u->get_location());
1198 map_location highlighted_hex = rc.screen().displayed_unit_hex();
1201 attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1203 if (!attack_loc.
valid())
1238 std::ostringstream text;
1241 const std::vector<time_of_day>& schedule = rc.
tod().
times(tod_schedule_hex);
1243 tooltip <<
_(
"Time of day schedule:") <<
" \n";
1247 if (i == current) tooltip <<
"<big><b>";
1248 tooltip << tod.name <<
"\n";
1249 if (i == current) tooltip <<
"</b></big>";
1253 int times = schedule.size();
1254 text << current + 1 <<
"/" << times;
1256 return text_report(text.str(), tooltip.str(),
"..schedule");
1260 map_location mouseover_hex = rc.screen().mouseover_hex();
1281 std::string lawful_color(
"white");
1282 std::string chaotic_color(
"white");
1283 std::string liminal_color(
"white");
1286 lawful_color = (b > 0) ?
"#0f0" :
"#f00";
1287 chaotic_color = (b < 0) ?
"#0f0" :
"#f00";
1290 liminal_color = (l > 0) ?
"#0f0" :
"#f00";
1292 tooltip <<
_(
"Time of day:") <<
" <b>" << tod.
name <<
"</b>\n" 1293 <<
_(
"Lawful units: ") <<
"<span foreground=\"" << lawful_color <<
"\">" 1296 <<
_(
"Chaotic units: ") <<
"<span foreground=\"" << chaotic_color <<
"\">" 1298 <<
_(
"Liminal units: ") <<
"<span foreground=\"" << liminal_color <<
"\">" 1301 std::string tod_image = tod.
image;
1308 return image_report(tod_image, tooltip.str(),
"time_of_day_" + tod.
id);
1312 map_location mouseover_hex = rc.screen().mouseover_hex();
1335 std::string lawful_color(
"white");
1336 std::string chaotic_color(
"white");
1337 std::string liminal_color(
"white");
1340 lawful_color = (bonus > 0) ?
"green" :
"red";
1341 chaotic_color = (bonus < 0) ?
"green" :
"red";
1344 liminal_color = (l > 0) ?
"green" :
"red";
1346 tooltip << local_tod.
name <<
'\n' 1347 <<
_(
"Lawful units: ") <<
"<span foreground=\"" << lawful_color <<
"\">" 1350 <<
_(
"Chaotic units: ") <<
"<span foreground=\"" << chaotic_color <<
"\">" 1352 <<
_(
"Liminal units: ") <<
"<span foreground=\"" << liminal_color <<
"\">" 1355 std::string local_tod_image =
"themes/classic/" + local_tod.
image;
1356 std::string global_tod_image =
"themes/classic/" + global_tod.
image;
1358 local_tod_image +=
"~BLIT(";
1361 local_tod_image +=
")";
1376 std::string bg_terrain_image;
1380 bg_terrain_image =
"~BLIT(unit_env/terrain/terrain-" + terrain_id +
".png)" + bg_terrain_image;
1383 std::stringstream color;
1384 color << local_tod.
color;
1386 bg_terrain_image = bg_terrain_image +
"~CS(" + color.str() +
")";
1389 std::string unit_image;
1393 std::string tod_image = global_tod_image +
"~BLIT(" + local_tod_image +
")";
1395 return image_report(tod_image + bg_terrain_image + unit_image, tooltip.str(),
"time_of_day");
1399 map_location mouseover_hex = rc.screen().mouseover_hex();
1406 std::ostringstream str,
tooltip;
1407 str << rc.tod().turn();
1408 int nb = rc.tod().number_of_turns();
1409 if (nb != -1) str <<
'/' << nb;
1411 tooltip <<
_(
"Turn Number");
1413 tooltip <<
"\n\n" <<
_(
"When the game exceeds the number of turns indicated by the second number, it will end.");
1420 std::ostringstream str;
1421 int viewing_side = rc.screen().viewing_side();
1423 int fake_gold = rc.dc().get_team(viewing_side).gold();
1426 fake_gold -= rc.wb()->get_spent_gold_for(viewing_side);
1427 char const *end =
naps;
1428 if (viewing_side != rc.screen().playing_side()) {
1431 else if (fake_gold < 0) {
1438 return text_report(str.str(),
_(
"Gold") +
"\n\n" +
_(
"The amount of gold currently available to recruit and maintain your army."));
1443 std::ostringstream str;
1444 int viewing_side = rc.screen().viewing_side();
1445 const team &viewing_team = rc.dc().get_team(viewing_side);
1446 str << viewing_team.
villages().size() <<
'/';
1448 int unshrouded_villages = 0;
1451 ++unshrouded_villages;
1453 str << unshrouded_villages;
1455 str << rc.map().villages().size();
1457 return gray_inactive(rc,str.str(),
_(
"Villages") +
"\n\n" +
_(
"The fraction of known villages that your side has captured."));
1462 return gray_inactive(rc, std::to_string(rc.dc().side_units(rc.screen().viewing_side())),
_(
"Units") +
"\n\n" +
_(
"The total number of units on your side."));
1467 std::ostringstream str;
1468 int viewing_side = rc.screen().viewing_side();
1469 const team &viewing_team = rc.dc().get_team(viewing_side);
1471 str << td.
expenses <<
" (" << td.upkeep <<
")";
1472 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."));
1477 int viewing_side = rc.screen().viewing_side();
1478 const team &viewing_team = rc.dc().get_team(viewing_side);
1485 std::ostringstream str;
1486 int viewing_side = rc.screen().viewing_side();
1487 const team &viewing_team = rc.dc().get_team(viewing_side);
1489 char const *end =
naps;
1490 if (viewing_side != rc.screen().playing_side()) {
1491 if (td.net_income < 0) {
1492 td.net_income = - td.net_income;
1500 else if (td.net_income < 0) {
1501 td.net_income = - td.net_income;
1508 str << td.net_income << end;
1509 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."));
1513 void blit_tced_icon(
config &cfg,
const std::string &terrain_id,
const std::string &icon_image,
bool high_res,
1514 const std::string &terrain_name) {
1515 const std::string tc_base = high_res ?
"images/buttons/icon-base-32.png" :
"images/buttons/icon-base-16.png";
1516 const std::string terrain_image =
"terrain/" + icon_image + (high_res ?
"_30.png" :
".png");
1517 add_image(cfg, tc_base +
"~RC(magenta>" + terrain_id +
")~BLIT(" + terrain_image +
")", terrain_name);
1523 const gamemap &map = rc.map();
1524 map_location mouseover_hex = rc.screen().mouseover_hex();
1527 mouseover_hex = rc.screen().selected_hex();
1538 bool high_res =
false;
1560 if (terrain_icon.empty())
1562 blit_tced_icon(cfg, terrain_id, terrain_icon, high_res, terrain_name);
1569 const gamemap &map = rc.map();
1570 int viewing_side = rc.screen().viewing_side();
1571 const team &viewing_team = rc.dc().get_team(viewing_side);
1572 map_location mouseover_hex = rc.screen().mouseover_hex();
1580 std::ostringstream str;
1583 int owner = rc.dc().village_owner(mouseover_hex);
1584 if (owner == 0 || viewing_team.
fogged(mouseover_hex)) {
1586 }
else if (owner == viewing_side) {
1588 }
else if (viewing_team.
is_enemy(owner)) {
1595 if(!underlying_desc.empty()) {
1596 str << underlying_desc;
1607 std::ostringstream text;
1609 std::ostringstream
help;
1611 text << static_cast<int>(rc.screen().get_zoom_factor() * 100) <<
"%";
1613 return text_report(text.str(), tooltip.str(), help.str());
1618 const gamemap &map = rc.map();
1619 map_location mouseover_hex = rc.screen().mouseover_hex(),
1620 displayed_unit_hex = rc.screen().displayed_unit_hex(),
1621 selected_hex = rc.screen().selected_hex();
1623 if (!map.
on_board(mouseover_hex)) {
1627 mouseover_hex = selected_hex;
1635 std::ostringstream str;
1636 str << mouseover_hex;
1639 const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1641 (displayed_unit_hex != mouseover_hex &&
1642 displayed_unit_hex != rc.screen().selected_hex()) ||
1643 viewing_team.
shrouded(mouseover_hex))
1649 str <<
" " << defense <<
"%," << move_cost;
1650 }
else if (mouseover_hex == displayed_unit_hex) {
1651 str <<
" " << defense <<
"%,‒";
1660 const team &active_team = rc.teams()[rc.screen().playing_team()];
1664 std::string mods =
"~RC(" + old_rgb +
">" + new_rgb +
")";
1665 if (flag_icon.empty())
1672 const std::set<std::string> &observers = rc.screen().observers();
1673 if (observers.empty())
1676 std::ostringstream str;
1677 str <<
_(
"Observers:") <<
'\n';
1678 for (
const std::string &obs : observers) {
1711 std::ostringstream ss;
1717 std::time_t
t = std::time(
nullptr);
1718 ss << std::put_time(std::localtime(&t), format);
1737 int viewing_side = rc.screen().viewing_side();
1738 const team &viewing_team = rc.dc().get_team(viewing_side);
1741 return report_report_clock(rc);
1742 std::ostringstream str;
1744 char const *end =
naps;
1745 if (viewing_side != rc.screen().playing_side())
1748 str <<
"<span foreground=\"#c80000\">";
1750 str <<
"<span foreground=\"#c8c800\">";
1756 if (sec < 10) str <<
'0';
1761 add_text(report, str.str(),
_(
"Turn Countdown") +
"\n\n" +
_(
"Countdown until your turn automatically ends."));
1768 dynamic_generators_[name].reset(g);
1774 dynamic_report_generators::const_iterator
i = dynamic_generators_.find(name);
1775 if (i != dynamic_generators_.end())
1776 return i->second->generate(rc);
1780 return j->second(rc);
1786 if (!all_reports_.empty())
return all_reports_;
1788 all_reports_.insert(v.first);
1790 for (
const dynamic_report_generators::value_type &v : dynamic_generators_) {
1791 all_reports_.insert(v.first);
1793 return all_reports_;
const_attack_ptr weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
static config unit_level(const unit *u)
const gamemap & map() const
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
static config unit_xp(const unit *u)
const t_translation::ter_list & underlying_union_terrain(const map_location &loc) const
static std::string _n(const char *str1, const char *str2, int n)
int get_max_liminal_bonus() const
const t_translation::ter_list & underlying_def_terrain(const map_location &loc) const
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
int countdown_time() const
static display * get_singleton()
Returns the display object if a display object exists.
static int get_acceleration()
virtual const map_location & displayed_unit_hex() const
Virtual functions shadowed in game_display.
const team & get_team(int side) const
const t_string & description() const
int jamming() const
Gets the unit's jamming points.
int vision() const
Gets the unit's vision points.
const std::string weapon_details_sep
This class represents a single unit of a specific type.
const std::string & type_id() const
The id of this unit's type.
const color_t inactive_details_color
const std::vector< team > & teams() const
static config time_of_day_at(reports::context &rc, const map_location &mouseover_hex)
tod_color color
The color modifications that should be made to the game board to reflect the time of day...
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit's movement cost on a particular terrain.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
const unit * get_visible_unit(const map_location &loc, const team ¤t_team, bool see_all=false) const
static config unit_advancement_options(const unit *u)
std::string get_underlying_terrain_string(const t_translation::terrain_code &terrain) const
const map_location & selected_hex() const
Various functions that implement attacks and attack calculations.
const std::string & id() const
const std::string & side_name() const
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
bool terrain_matches(const terrain_code &src, const terrain_code &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
unit_race::GENDER gender() const
The gender of this unit.
const map_location & get_attack_indicator_src()
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
int hitpoints() const
The current number of hitpoints this unit has.
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.
static void add_status(config &r, char const *path, char const *desc1, char const *desc2)
static int attack_info(reports::context &rc, const attack_type &at, config &res, const unit &u, const map_location &hex, const unit *sec_u=nullptr, const_attack_ptr sec_u_weapon=nullptr)
int get_current_time(const map_location &loc=map_location::null_location()) const
int under_leadership(const unit &u, const map_location &loc, const_attack_ptr weapon, const_attack_ptr opp_weapon)
Tests if the unit at loc is currently affected by leadership.
static config image_report(const std::string &image, const std::string &tooltip="", const std::string &help="")
bool show_everything() const
const std::set< std::string > & report_list()
static std::string format_hp(unsigned hp)
int lawful_bonus
The % bonus lawful units receive.
const color_t good_dmg_color
void modified_attacks(bool is_backstab, unsigned &min_attacks, unsigned &max_attacks) const
Calculates the number of attacks this weapon has, considering specials.
The unit is slowed - it moves slower and does less damage.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
static config text_report(const std::string &text, const std::string &tooltip="", const std::string &help="")
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
std::string image
The image to be displayed in the game status.
static std::string format_prob(double prob)
The unit is poisoned - it loses health each turn.
std::string absolute_image() const
The name of the file to game_display (used in menus).
constexpr int round_damage(int base_damage, int bonus, int divisor)
round (base_damage * bonus / divisor) to the closest integer, but up or down towards base_damage ...
const std::string & type() const
const t_string & income_description() const
static config unit_side(reports::context &rc, const unit *u)
static config unit_name(const unit *u)
const tod_manager & tod() const
static config unit_traits(const unit *u)
report_generator_helper(const char *name, reports::generator_function g)
static config unit_type(const unit *u)
static const color_t attack_info_percent_color(int resistance)
Maps resistance <= -60 (resistance value <= -60%) to intense red.
static std::string _(const char *str)
static config tod_stats_at(reports::context &rc, const map_location &hex)
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
std::vector< std::tuple< std::string, t_string, t_string, t_string > > ability_tooltips() const
Gets the names and descriptions of this unit's abilities.
A single unit type that the player may recruit.
bool is_nonnull() const
True if this object represents some sentinel values.
std::string get_terrain_string(const map_location &loc) const
const t_string & name(GENDER gender=MALE) const
static config gray_inactive(reports::context &rc, const std::string &str, const std::string &tooltip="")
const terrain_code VOID_TERRAIN
VOID_TERRAIN is used for shrouded hexes.
const color_t weapon_color
static config unit_abilities(const unit *u, const map_location &loc)
const unit_type & type() const
This unit's type, accounting for gender and variation.
static static_report_generators static_generators
static const t_string get_side_color_name_for_UI(unsigned side)
color_t hp_color() const
Color for this unit's current hitpoints.
std::shared_ptr< const unit > unit_const_ptr
Object which defines a time of day with associated bonuses, image, sounds etc.
static config unit_weapons(reports::context &rc, unit_const_ptr attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
static config unit_race(const unit *u)
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
std::string span_color(const color_t &color)
Returns a Pango formatting string using the provided color_t object.
This class stores all the data for a single 'side' (in game nomenclature).
Belongs to a non-friendly side; normally visualised by not displaying an orb.
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
static std::string at(const std::string &file, int line)
const color_t bad_dmg_color
int damage
Effective damage of the weapon (all factors accounted for).
const std::string unicode_minus
static config unit_alignment(reports::context &rc, const unit *u, const map_location &hex)
const std::string & id() const
Gets this unit's id.
const terrain_code FOGGED
#define REPORT_GENERATOR(n, cn)
void register_generator(const std::string &name, generator *)
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
static const time_of_day get_visible_time_of_day_at(reports::context &rc, const map_location &hex)
const pathfind::marked_route & get_route()
Gets the route along which footsteps are drawn to show movement of a unit.
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
color_t xp_color() const
Color for this unit's XP.
const t_string & name() const
config generate_report(const std::string &name, context &ct, bool only_static=false)
Encapsulates the map of the game.
const t_string & name() const
Gets this unit's translatable display name.
The basic class for representing 8-bit RGB or RGBA colour values.
Computes the statistics of a battle between an attacker and a defender unit.
utils::string_map_res get_base_resistances() const
Gets resistances without any abilities applied.
int max_experience() const
The max number of experience points this unit can have.
std::set< t_translation::terrain_code > & encountered_terrains()
const std::string & range() const
bool is_enemy(int n) const
void fight(combatant &opponent, bool levelup_considered=true)
Simulate a fight! Can be called multiple times for cumulative calculations.
std::vector< std::pair< t_string, t_string > > special_tooltips(boost::dynamic_bitset<> *active_list=nullptr) const
Returns a vector of names and descriptions for the specials of *this.
virtual int playing_side() const
int level() const
The current level of this unit.
std::vector< t_string > unit_special_notes() const
The unit's special notes.
const std::vector< t_string > & trait_names() const
Gets the names of the currently registered traits.
const std::string & icon() const
static config unit_hp(reports::context &rc, const unit *u)
Structure describing the statistics of a unit involved in the battle.
const t_string & type_name() const
Gets the translatable name of this unit's type.
std::string small_profile() const
An optional profile image to display in Help.
Structure which holds a single route and marks for special events.
const std::string unicode_figure_dash
unit_alignments::type alignment() const
The alignment of this unit.
Generic locator abstracting the location of an image.
std::function< config(reports::context &)> generator_function
static std::string get_side_color_id(unsigned side)
static config unit_status(reports::context &rc, const unit *u)
Encapsulates the map of the game.
static const unit * get_visible_unit(reports::context &rc)
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp, unsigned max_hp)
Calculates the number of blows resulting from swarm.
static config unit_box_at(reports::context &rc, const map_location &mouseover_hex)
bool invisible(const map_location &loc, bool see_all=true) const
static std::string side_tooltip(const team &team)
const color_t weapon_details_color
bool shrouded(const map_location &loc) const
const 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.
std::string id
Text to match against addon_info.tags()
static std::string gettext(const char *str)
std::string escape_text(const std::string &text)
Escapes the pango markup characters in a text.
const display_context & dc() const
const std::string unicode_en_dash
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
int max_hitpoints() const
The max number of hitpoints this unit can have.
std::string resistance_color(const int resistance)
Maps resistance <= -60 (resistance value <= -60%) to intense red.
static const unit * get_selected_unit(reports::context &rc)
static void add_image(config &report, const std::string &image, const std::string &tooltip, const std::string &help="")
static map_location::DIRECTION s
bool show_variations_in_help() const
Whether the unit type has at least one help-visible variation.
const std::string & flag_icon() const
const unit_map & units() const
t_translation::terrain_code number() const
const std::vector< time_of_day > & times(const map_location &loc=map_location::null_location()) const
const t_string & income_description_own() const
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
std::string signed_percent(int val)
Convert into a percentage (using the Unicode "−" and +0% convention.
const t_string & income_description_enemy() const
attack_itors attacks()
Gets an iterator over this unit's attacks.
std::map< std::string, std::string > advancement_icons() const
Gets and image path and and associated description for each advancement option.
std::string accuracy_parry_description() const
static std::string flush(std::ostringstream &s)
double get_battery_percentage()
int modified_damage(bool is_backstab) const
Returns the damage per attack of this weapon, considering specials.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
const t_translation::ter_list & union_type() const
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has.
static std::string unit_level_tooltip(const int level, const std::vector< std::string > &adv_to_types, const std::vector< config > &adv_to_mods)
const unit_race * race() const
Gets this unit's race.
static unit_const_ptr get_selected_unit_ptr(reports::context &rc)
const std::string unicode_bullet
color_t blue_to_white(double val, bool for_text)
static config unit_defense(reports::context &rc, const unit *u, const map_location &displayed_unit_hex)
config & add_child(config_key_type key)
const t_string & name() const
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
static std::string alignment_description(unit_alignments::type align, unit_race::GENDER gender=unit_race::MALE)
Implementation detail of unit_type::alignment_description.
std::map< std::string, reports::generator_function > static_report_generators
bool is_village(const map_location &loc) const
unit_const_ptr get_visible_unit_shared_ptr(const map_location &loc, const team ¤t_team, bool see_all=false) const
const std::string & color() const
const ter_match ALL_OFF_MAP
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
const std::string weapon_numbers_sep
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 experience() const
The current number of experience points this unit has.
const map_location & get_location() const
The current map location this unit is at.
symbol_table string_table
std::size_t viewing_team() const
The viewing team is the team currently viewing the game.
static void add_text(config &report, const std::string &text, const std::string &tooltip, const std::string &help="")
Functions to load and save images from/to disk.
bool can_advance() const
Checks whether this unit has any options to advance to.
const std::string & id() const
std::vector< terrain_code > ter_list
specials_context_t specials_context_for_listing(bool attacking=true) const
static config unit_moves(reports::context &rc, const unit *u, bool is_visible_unit)
t_string unit_description() const
A detailed description of this unit.
static const map_location & null_location()
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.0, passing by yellow.
int total_movement() const
The maximum moves this unit has.
unsigned int num_blows
Effective number of blows, takes swarm into account.
std::string base_str() const
bool fogged(const map_location &loc) const
const t_string & income_description_ally() const
int side() const
The side this unit belongs to.
specials_context_t specials_context(unit_const_ptr self, unit_const_ptr other, const map_location &unit_loc, const map_location &other_loc, bool attacking, const_attack_ptr other_attack) const
std::string signed_value(int val)
Convert into a signed value (using the Unicode "−" and +0 convention.
int resistance_against(const std::string &damage_name, bool attacker, const map_location &loc, const_attack_ptr weapon=nullptr, const_attack_ptr opp_weapon=nullptr) const
The unit's resistance against a given damage type.
std::vector< std::pair< std::string, std::string > > amla_icons() const
Gets the image and description data for modification advancements.
A config object defines a single node in a WML file, with access to child nodes.
std::shared_ptr< const attack_type > const_attack_ptr
static config unit_vision(const unit *u)
const std::set< map_location > & villages() const
This module contains various pathfinding functions and utilities.
bool file_exists() const
Tests whether the file the locator points at exists.
bool use_twelve_hour_clock_format()
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
std::vector< map_location > & steps
int max_attacks() const
The maximum number of attacks this unit may perform per turn, usually 1.
const std::string & icon_image() const
std::string tooltip
Shown when hovering over an entry in the filter's drop-down list.
static game_display * get_singleton()
const std::vector< t_string > & trait_descriptions() const
Gets the descriptions of the currently registered traits.
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
const color_t inactive_ability_color