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;
55 if (!
help.empty()) element[
"help"] =
help;
59 const std::string &
tooltip,
const std::string &
help =
"")
62 element[
"image"] =
image;
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(const reports::context& cn); \
127 static report_generator_helper reg_gen_##n(#n, &report_##n); \
128 static config report_##n(const 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;
198 tooltip <<
"\n\n" <<
_(
"Special Notes:") <<
'\n';
199 for(
const auto& note : notes) {
219 std::ostringstream str,
tooltip;
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 +
")";
258 std::stringstream text;
259 text <<
" " << u->
side();
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"
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."));
357 add_status(res,
"misc/unhealable.png",
N_(
"unhealable: "),
358 N_(
"This unit is unhealable. It cannot be healed by healers or villages and doesn’t benefit from resting."));
361 add_status(res,
"misc/invulnerable.png",
N_(
"invulnerable: "),
362 N_(
"This unit is invulnerable. It cannot be harmed by any attack."));
380 std::ostringstream str,
tooltip;
393 tooltip <<
_(
"Alignment: ") <<
"<b>" << align <<
"</b>\n"
401 const map_location& mouseover_hex = rc.screen().mouseover_hex();
402 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
403 const map_location& hex = mouseover_hex.
valid() ? mouseover_hex : displayed_unit_hex;
420 boost::dynamic_bitset<> active;
423 const std::size_t abilities_size = abilities.size();
424 for(std::size_t
i = 0;
i != abilities_size; ++
i) {
426 const auto& [
id,
base_name, display_name, description] = abilities[
i];
428 std::ostringstream str,
tooltip;
436 if(
i + 1 != abilities_size) {
440 tooltip <<
_(
"Ability: ") <<
"<b>" << display_name <<
"</b>";
442 tooltip <<
"<i>" <<
_(
" (inactive)") <<
"</i>";
445 tooltip <<
'\n' << description;
455 const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
456 const map_location& mouseover_hex = rc.screen().mouseover_hex();
457 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
458 const map_location& hex = (mouseover_hex.
valid() && !viewing_team.
shrouded(mouseover_hex)) ? mouseover_hex : displayed_unit_hex;
466 const map_location& mouseover_hex = rc.screen().mouseover_hex();
468 const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
470 if (visible_unit && u && visible_unit->
id() != u->
id() && mouseover_hex.
valid() && !viewing_team.
shrouded(mouseover_hex))
480 std::ostringstream str,
tooltip;
484 std::vector<std::string> resistances_table;
486 bool att_def_diff =
false;
490 std::ostringstream
line;
496 if (res_att == res_def) {
507 resistances_table.push_back(
line.str());
514 for (
const std::string &
line : resistances_table) {
533 std::ostringstream str,
tooltip;
543 tooltip <<
_(
"Experience Modifier: ") << exp_mod <<
'%';
583 std::ostringstream str,
tooltip;
596 if (underlyings.size() != 1 || underlyings.front() != terrain)
610 << (revert ?
_(
"maximum^max.") :
_(
"minimum^min.")) <<
'\n';
622 const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
623 const map_location& mouseover_hex = rc.screen().mouseover_hex();
624 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
625 const map_location& hex = (mouseover_hex.
valid() && !viewing_team.
shrouded(mouseover_hex)) ? mouseover_hex : displayed_unit_hex;
632 if(attack_indicator_src.
valid())
635 const map_location& mouseover_hex = rc.screen().mouseover_hex();
637 if(visible_unit && u && visible_unit->
id() != u->
id() && mouseover_hex.
valid())
648 std::ostringstream str,
tooltip;
650 str <<
_(
"vision:") <<
' ' << u->
vision();
654 if (
static_cast<std::streamoff
>(str.tellp()) == 0)
655 str <<
_(
"jamming:") <<
' ' << u->
jamming();
674 std::ostringstream str,
tooltip;
675 double movement_frac = 1.0;
677 std::set<terrain_movement> terrain_moves;
681 if (movement_frac > 1.0)
685 tooltip <<
_(
"Movement Costs:") <<
"\n";
692 if (
info.union_type().size() == 1 &&
info.union_type()[0] ==
info.number() &&
info.is_nonnull()) {
702 double movement_red_to_green = 100.0 - 25.0 * tm.moves;
706 tooltip <<
"<span foreground=\"" << color <<
"\">";
711 }
else if (cannot_move) {
712 tooltip <<
"(" << tm.moves <<
")";
717 const int movement_hexes_per_turn = u->
total_movement() / tm.moves;
719 for(
int i = 0;
i < movement_hexes_per_turn; ++
i) {
727 int grey = 128 +
static_cast<int>((255 - 128) * movement_frac);
730 if(is_visible_unit) {
732 if(route.
steps.size() > 0) {
741 const auto& end = route.
marks.find(route.
steps.back());
742 if(end != route.
marks.end() && end->second.capture) {
779 std::ostringstream str,
tooltip;
782 struct string_with_tooltip {
789 int base_damage =
at.damage();
790 int specials_damage =
at.modified_damage();
791 int damage_multiplier = 100;
794 damage_multiplier += tod_bonus;
796 if (leader_bonus != 0)
797 damage_multiplier += leader_bonus;
800 int damage_divisor =
slowed ? 20000 : 10000;
802 damage =
round_damage(specials_damage, damage_multiplier * 100, damage_divisor);
806 unsigned cur_hp = std::min<unsigned>(std::max(0, u.
hitpoints()), max_hp);
808 unsigned base_attacks =
at.num_attacks();
809 unsigned min_attacks, max_attacks;
810 at.modified_attacks(min_attacks, max_attacks);
811 unsigned num_attacks =
swarm_blows(min_attacks, max_attacks, cur_hp, max_hp);
814 if ( damage > specials_damage )
816 else if ( damage < specials_damage )
822 tooltip <<
_(
"Weapon: ") <<
"<b>" <<
at.name() <<
"</b>\n"
823 <<
_(
"Damage: ") <<
"<b>" << damage <<
"</b>\n";
825 if ( tod_bonus || leader_bonus ||
slowed || specials_damage != base_damage )
827 tooltip <<
'\t' <<
_(
"Base damage: ") << base_damage <<
'\n';
828 if ( specials_damage != base_damage ) {
829 tooltip <<
'\t' <<
_(
"With specials: ") << specials_damage <<
'\n';
832 tooltip <<
'\t' <<
_(
"Time of day: ")
836 tooltip <<
'\t' <<
_(
"Leadership: ")
840 tooltip <<
'\t' <<
_(
"Slowed: ") <<
"/ 2" <<
'\n';
844 tooltip <<
_(
"Attacks: ") <<
"<b>" << num_attacks <<
"</b>\n";
845 if ( max_attacks != min_attacks && cur_hp != max_hp ) {
846 if ( max_attacks < min_attacks ) {
848 tooltip <<
'\t' <<
_(
"Max swarm bonus: ") << (min_attacks-max_attacks) <<
'\n';
849 tooltip <<
'\t' <<
_(
"Swarm: ") <<
"* "<< (100 - cur_hp*100/max_hp) <<
"%\n";
850 tooltip <<
'\t' <<
_(
"Base attacks: ") <<
'+' << base_attacks <<
'\n';
854 if ( max_attacks != base_attacks ) {
855 int attack_diff =
static_cast<int>(max_attacks) -
static_cast<int>(base_attacks);
861 tooltip <<
'\t' <<
_(
"Base attacks: ") << base_attacks <<
'\n';
862 if ( max_attacks != base_attacks ) {
863 tooltip <<
'\t' <<
_(
"With specials: ") << max_attacks <<
'\n';
865 if ( min_attacks != 0 ) {
866 tooltip <<
'\t' <<
_(
"Subject to swarm: ") << (max_attacks-min_attacks) <<
'\n';
868 tooltip <<
'\t' <<
_(
"Swarm: ") <<
"* "<< (cur_hp*100/max_hp) <<
"%\n";
871 else if ( num_attacks != base_attacks ) {
872 tooltip <<
'\t' <<
_(
"Base attacks: ") << base_attacks <<
'\n';
873 tooltip <<
'\t' <<
_(
"With specials: ") << num_attacks <<
'\n';
879 std::pair<std::string, std::string> types =
at.damage_type();
880 std::string secondary_lang_type = types.second;
881 if (!secondary_lang_type.empty()) {
882 secondary_lang_type =
", " +
string_table[
"type_" + secondary_lang_type];
884 std::string lang_type =
string_table[
"type_" + types.first] + secondary_lang_type;
887 const std::string range_png = std::string(
"icons/profiles/") +
at.range() +
"_attack.png~SCALE_INTO(16,16)";
888 const std::string type_png = std::string(
"icons/profiles/") + types.first +
".png~SCALE_INTO(16,16)";
889 const std::string secondary_type_png = !(types.second).empty() ? std::string(
"icons/profiles/") + types.second +
".png~SCALE_INTO(16,16)" :
"";
894 if(!range_png_exists || !type_png_exists || (!secondary_type_png_exists && !secondary_lang_type.empty())) {
897 << lang_type <<
"</span>\n";
900 tooltip <<
_(
"Weapon range: ") <<
"<b>" << range <<
"</b>\n"
901 <<
_(
"Damage type: ") <<
"<b>" << lang_type <<
"</b>\n"
902 <<
_(
"Damage versus: ") <<
'\n';
906 std::map<int, std::set<std::string>, std::greater<int>> resistances;
907 std::set<std::string> seen_types;
912 if (
enemy.incapacitated())
918 if (!
enemy.is_visible_to_team(viewing_team, see_all))
920 bool new_type = seen_types.insert(
enemy.type_id()).second;
922 int resistance =
enemy.resistance_against(
at,
false, loc);
923 resistances[resistance].insert(
enemy.type_name());
927 for (
const auto& resist : resistances) {
928 int damage_with_resistance =
round_damage(specials_damage, damage_multiplier * resist.first, damage_divisor);
929 tooltip <<
"<b>" << damage_with_resistance <<
"</b> "
942 const std::string attack_icon =
at.icon() +
"~SCALE_INTO_SHARP(60,60)~CROP(2,2,56,56)~SCALE_INTO_SHARP(32,32)";
948 const std::string spacer =
"misc/blank.png~CROP(0, 0, 16, 21)";
949 add_image(res, spacer +
"~BLIT(" + range_png +
",0,5)", damage_versus.tooltip);
950 add_image(res, spacer +
"~BLIT(" + type_png +
",0,5)", damage_versus.tooltip);
951 if(secondary_type_png_exists){
952 add_image(res, spacer +
"~BLIT(" + secondary_type_png +
",0,5)", damage_versus.tooltip);
954 add_text(res, damage_and_num_attacks.str, damage_and_num_attacks.tooltip);
955 add_text(res, damage_versus.str, damage_versus.tooltip);
957 const std::string &accuracy_parry =
at.accuracy_parry_description();
958 if (!accuracy_parry.empty())
961 <<
" " << accuracy_parry <<
"</span>\n";
962 int accuracy =
at.accuracy();
967 int parry =
at.parry();
979 auto ctx = (sec_u ==
nullptr) ?
at.specials_context_for_listing(attacking) :
980 at.specials_context(u.shared_from_this(), sec_u->shared_from_this(), hex, sec_u->get_location(), attacking, sec_u_weapon);
982 boost::dynamic_bitset<> active;
983 const std::vector<std::pair<t_string, t_string>> &specials =
at.special_tooltips(&active);
984 const std::size_t specials_size = specials.size();
985 for ( std::size_t
i = 0;
i != specials_size; ++
i )
988 const t_string &name = specials[
i].first;
989 const t_string &description = specials[
i].second;
993 str <<
span_color(details_color) <<
" " <<
" " << name <<
naps <<
'\n';
994 std::string help_page =
"weaponspecial_" + name.
base_str();
995 tooltip <<
_(
"Weapon special: ") <<
"<b>" << name <<
"</b>";
997 tooltip <<
"<i>" <<
_(
" (inactive)") <<
"</i>";
998 tooltip <<
'\n' << description;
1002 if(!specials.empty()) {
1007 const std::string spacer =
"misc/blank.png~CROP(0, 0, 1, 5)";
1020 }
else if(prob < 0.0005) {
1023 std::ostringstream res;
1024 res << std::setprecision(prob < 0.01 ? 1 : prob < 0.1 ? 2 : 3) << 100.0 * prob <<
"%";
1030 std::ostringstream res;
1031 res <<
' ' << std::setw(3) << hp;
1037 if (!attacker || !defender)
return config();
1039 const unit* u = show_attacker ? attacker.get() : defender;
1040 const unit* sec_u = !show_attacker ? attacker.get() : defender;
1043 std::ostringstream str,
tooltip;
1046 std::vector<battle_context> weapons;
1047 for (
unsigned int i = 0;
i < attacker->attacks().
size();
i++) {
1049 if (attacker->attacks()[
i].attack_weight() > 0) {
1050 weapons.emplace_back(rc.
units(), attacker_pos, defender->
get_location(),
i, -1, 0.0,
nullptr, attacker);
1057 combatant attacker_combatant(weapon.get_attacker_stats());
1058 combatant defender_combatant(weapon.get_defender_stats());
1059 attacker_combatant.
fight(defender_combatant);
1062 show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
1064 !show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
1066 int total_damage = 0;
1067 int base_damage = 0;
1069 int chance_to_hit = 0;
1070 t_string weapon_name =
_(
"weapon^None");
1073 if (context_unit_stats.
weapon) {
1074 base_damage =
attack_info(rc, *context_unit_stats.
weapon, res, *u, unit_loc, sec_u, other_context_unit_stats.
weapon);
1075 total_damage = context_unit_stats.
damage;
1076 num_blows = context_unit_stats.
num_blows;
1078 weapon_name = context_unit_stats.
weapon->name();
1080 if ( total_damage > base_damage )
1082 else if ( total_damage < base_damage )
1086 tooltip <<
_(
"Weapon: ") <<
"<b>" << weapon_name <<
"</b>\n"
1087 <<
_(
"Damage: ") <<
"<b>" <<
"0" <<
"</b>\n";
1095 <<
" (" <<
span_color(chance_color) << chance_to_hit <<
"%" <<
naps <<
")"
1098 tooltip <<
_(
"Weapon: ") <<
"<b>" << weapon_name <<
"</b>\n"
1099 <<
_(
"Total damage") <<
"<b>" << total_damage <<
"</b>\n";
1102 std::vector<std::pair<int, double>> hp_prob_vector;
1105 std::vector<std::pair<double, int>> prob_hp_vector;
1108 combatant*
c = show_attacker ? &attacker_combatant : &defender_combatant;
1110 for(
i = 0; i < static_cast<int>(
c->hp_dist.size());
i++) {
1111 double prob =
c->hp_dist[
i];
1115 prob_hp_vector.emplace_back(prob,
i);
1118 std::sort(prob_hp_vector.begin(), prob_hp_vector.end());
1121 int max_hp_distrib_rows_ = 10;
1124 int nb_elem = std::min<int>(max_hp_distrib_rows_, prob_hp_vector.size());
1126 for(
i = prob_hp_vector.size() - nb_elem;
1127 i <
static_cast<int>(prob_hp_vector.size());
i++) {
1129 hp_prob_vector.emplace_back(prob_hp_vector[
i].second, prob_hp_vector[
i].first);
1133 std::sort(hp_prob_vector.begin(), hp_prob_vector.end());
1135 std::reverse(hp_prob_vector.begin(), hp_prob_vector.end());
1137 for(
i = 0; i < static_cast<int>(hp_prob_vector.size());
i++) {
1139 int hp = hp_prob_vector[
i].first;
1140 double prob = hp_prob_vector[
i].second;
1162 if ((u !=
nullptr) && (!u->
attacks().empty())) {
1163 const std::string attack_headline =
_n(
"Attack",
"Attacks", u->
attacks().size());
1166 + attack_headline +
"</span>" +
'\n',
"");
1171 const std::string
line =
VGETTEXT(
"Remaining: $left/$max",
1172 {{
"left", std::to_string(left)},
1173 {
"max", std::to_string(max)}});
1175 _(
"This unit can attack multiple times per turn."));
1188 const map_location& mouseover_hex = rc.screen().mouseover_hex();
1189 const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
1190 const map_location& hex = mouseover_hex.
valid() ? mouseover_hex : displayed_unit_hex;
1200 if (!u)
return report_unit_weapons(rc);
1201 if (!sec_u || u.get() == sec_u)
return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1203 map_location highlighted_hex = rc.screen().displayed_unit_hex();
1206 attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1208 if (!attack_loc.
valid())
1209 return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1220 if (!sec_u || u.get() == sec_u)
return unit_weapons(rc, u.get(), u->get_location());
1222 map_location highlighted_hex = rc.screen().displayed_unit_hex();
1225 attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1227 if (!attack_loc.
valid())
1262 std::ostringstream text;
1265 const std::vector<time_of_day>& schedule = rc.
tod().
times(tod_schedule_hex);
1267 tooltip <<
_(
"Time of day schedule:") <<
" \n";
1271 if (
i == current)
tooltip <<
"<big><b>";
1273 if (
i == current)
tooltip <<
"</b></big>";
1277 int times = schedule.size();
1278 text << current + 1 <<
"/" << times;
1284 map_location mouseover_hex = rc.screen().mouseover_hex();
1305 std::string lawful_color(
"white");
1306 std::string chaotic_color(
"white");
1307 std::string liminal_color(
"white");
1310 lawful_color = (
b > 0) ?
"#0f0" :
"#f00";
1311 chaotic_color = (
b < 0) ?
"#0f0" :
"#f00";
1314 liminal_color = (l > 0) ?
"#0f0" :
"#f00";
1316 tooltip <<
_(
"Time of day:") <<
" <b>" << tod.
name <<
"</b>\n"
1317 <<
_(
"Lawful units: ") <<
"<span foreground=\"" << lawful_color <<
"\">"
1320 <<
_(
"Chaotic units: ") <<
"<span foreground=\"" << chaotic_color <<
"\">"
1322 <<
_(
"Liminal units: ") <<
"<span foreground=\"" << liminal_color <<
"\">"
1325 std::string tod_image = tod.
image;
1336 map_location mouseover_hex = rc.screen().mouseover_hex();
1359 std::string lawful_color(
"white");
1360 std::string chaotic_color(
"white");
1361 std::string liminal_color(
"white");
1364 lawful_color = (bonus > 0) ?
"green" :
"red";
1365 chaotic_color = (bonus < 0) ?
"green" :
"red";
1368 liminal_color = (l > 0) ?
"green" :
"red";
1371 <<
_(
"Lawful units: ") <<
"<span foreground=\"" << lawful_color <<
"\">"
1374 <<
_(
"Chaotic units: ") <<
"<span foreground=\"" << chaotic_color <<
"\">"
1376 <<
_(
"Liminal units: ") <<
"<span foreground=\"" << liminal_color <<
"\">"
1379 std::string local_tod_image =
"themes/classic/" + local_tod.
image;
1380 std::string global_tod_image =
"themes/classic/" + global_tod.
image;
1382 local_tod_image +=
"~BLIT(";
1385 local_tod_image +=
")";
1400 std::string bg_terrain_image;
1404 bg_terrain_image =
"~BLIT(unit_env/terrain/terrain-" + terrain_id +
".png)" + bg_terrain_image;
1407 std::stringstream color;
1408 color << local_tod.
color;
1410 bg_terrain_image = bg_terrain_image +
"~CS(" + color.str() +
")";
1413 std::string unit_image;
1417 std::string tod_image = global_tod_image +
"~BLIT(" + local_tod_image +
")";
1419 return image_report(tod_image + bg_terrain_image + unit_image,
tooltip.str(),
"time_of_day");
1423 map_location mouseover_hex = rc.screen().mouseover_hex();
1430 std::ostringstream str,
tooltip;
1431 str << rc.tod().turn();
1432 int nb = rc.tod().number_of_turns();
1433 if (nb != -1) str <<
'/' << nb;
1437 tooltip <<
"\n\n" <<
_(
"When the game exceeds the number of turns indicated by the second number, it will end.");
1444 std::ostringstream str;
1445 int viewing_side = rc.screen().viewing_side();
1447 int fake_gold = rc.dc().get_team(viewing_side).gold();
1450 fake_gold -= rc.wb()->get_spent_gold_for(viewing_side);
1451 char const *end =
naps;
1452 if (viewing_side != rc.screen().playing_side()) {
1455 else if (fake_gold < 0) {
1462 return text_report(str.str(),
_(
"Gold") +
"\n\n" +
_(
"The amount of gold currently available to recruit and maintain your army."));
1467 std::ostringstream str;
1468 int viewing_side = rc.screen().viewing_side();
1469 const team &viewing_team = rc.dc().get_team(viewing_side);
1470 str << viewing_team.
villages().size() <<
'/';
1472 int unshrouded_villages = 0;
1475 ++unshrouded_villages;
1477 str << unshrouded_villages;
1479 str << rc.map().villages().size();
1481 return gray_inactive(rc,str.str(),
_(
"Villages") +
"\n\n" +
_(
"The fraction of known villages that your side has captured."));
1486 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."));
1491 std::ostringstream str;
1492 int viewing_side = rc.screen().viewing_side();
1493 const team &viewing_team = rc.dc().get_team(viewing_side);
1496 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."));
1501 int viewing_side = rc.screen().viewing_side();
1502 const team &viewing_team = rc.dc().get_team(viewing_side);
1509 std::ostringstream str;
1510 int viewing_side = rc.screen().viewing_side();
1511 const team &viewing_team = rc.dc().get_team(viewing_side);
1513 char const *end =
naps;
1514 if (viewing_side != rc.screen().playing_side()) {
1533 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."));
1537 void blit_tced_icon(
config &cfg,
const std::string &terrain_id,
const std::string &icon_image,
bool high_res,
1538 const std::string &terrain_name) {
1539 const std::string tc_base = high_res ?
"images/buttons/icon-base-32.png" :
"images/buttons/icon-base-16.png";
1540 const std::string terrain_image =
"terrain/" + icon_image + (high_res ?
"_30.png" :
".png");
1541 add_image(cfg, tc_base +
"~RC(magenta>" + terrain_id +
")~BLIT(" + terrain_image +
")", terrain_name);
1547 const gamemap& map = rc.map();
1548 map_location mouseover_hex = rc.screen().mouseover_hex();
1551 mouseover_hex = rc.screen().selected_hex();
1565 bool high_res =
false;
1587 if(terrain_icon.empty()) {
1590 blit_tced_icon(cfg, terrain_id, terrain_icon, high_res, terrain_name);
1594 int owner = rc.dc().village_owner(mouseover_hex);
1598 int viewing_side = rc.screen().viewing_side();
1599 const team& viewing_team = rc.dc().get_team(viewing_side);
1601 if(!viewing_team.
fogged(mouseover_hex)) {
1602 const team& owner_team = rc.dc().get_team(owner);
1607 std::string mods =
"~RC(" + old_rgb +
">" + new_rgb +
")";
1612 std::string side = std::to_string(owner_team.
side());
1625 const gamemap &map = rc.map();
1626 int viewing_side = rc.screen().viewing_side();
1627 const team &viewing_team = rc.dc().get_team(viewing_side);
1628 map_location mouseover_hex = rc.screen().mouseover_hex();
1636 std::ostringstream str;
1639 int owner = rc.dc().village_owner(mouseover_hex);
1640 if (owner == 0 || viewing_team.
fogged(mouseover_hex)) {
1642 }
else if (owner == viewing_side) {
1644 }
else if (viewing_team.
is_enemy(owner)) {
1651 if(!underlying_desc.empty()) {
1652 str << underlying_desc;
1663 std::ostringstream text;
1665 std::ostringstream
help;
1667 text << static_cast<int>(rc.screen().get_zoom_factor() * 100) <<
"%";
1674 const gamemap &map = rc.map();
1675 map_location mouseover_hex = rc.screen().mouseover_hex(),
1676 displayed_unit_hex = rc.screen().displayed_unit_hex(),
1677 selected_hex = rc.screen().selected_hex();
1679 if (!map.
on_board(mouseover_hex)) {
1683 mouseover_hex = selected_hex;
1691 std::ostringstream str;
1692 str << mouseover_hex;
1695 const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1697 (displayed_unit_hex != mouseover_hex &&
1698 displayed_unit_hex != rc.screen().selected_hex()) ||
1699 viewing_team.
shrouded(mouseover_hex))
1705 str <<
" " << defense <<
"%," << move_cost;
1706 }
else if (mouseover_hex == displayed_unit_hex) {
1707 str <<
" " << defense <<
"%,‒";
1716 const team &active_team = rc.teams()[rc.screen().playing_team()];
1720 std::string mods =
"~RC(" + old_rgb +
">" + new_rgb +
")";
1728 const std::set<std::string> &observers = rc.screen().observers();
1729 if (observers.empty())
1732 std::ostringstream str;
1733 str <<
_(
"Observers:") <<
'\n';
1734 for (
const std::string &obs : observers) {
1745 std::ostringstream ss;
1751 std::time_t
t = std::time(
nullptr);
1752 ss << std::put_time(std::localtime(&
t),
format);
1771 int viewing_side = rc.screen().viewing_side();
1772 const team &viewing_team = rc.dc().get_team(viewing_side);
1775 return report_report_clock(rc);
1776 std::ostringstream str;
1778 char const *end =
naps;
1779 if (viewing_side != rc.screen().playing_side())
1782 str <<
"<span foreground=\"#c80000\">";
1784 str <<
"<span foreground=\"#c8c800\">";
1790 if (sec < 10) str <<
'0';
1795 add_text(report, str.str(),
_(
"Turn Countdown") +
"\n\n" +
_(
"Countdown until your turn automatically ends."));
1810 return i->second->generate(rc);
1814 return j->second(rc);
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.
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.
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(config_key_type 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
int viewing_side() const
The 1-based equivalent of the 0-based viewing_team() function.
std::size_t viewing_team() const
The viewing team is the team currently viewing the game.
virtual int playing_side() 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 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.
const t_translation::ter_list & underlying_union_terrain(const map_location &loc) const
bool is_village(const map_location &loc) const
std::string get_underlying_terrain_string(const t_translation::terrain_code &terrain) const
const t_translation::ter_list & underlying_def_terrain(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
Generic locator abstracting the location of an image.
bool file_exists() const
Tests whether the file the locator points at exists.
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
const display_context & dc() const
const std::vector< team > & teams() const
const unit_map & units() const
const tod_manager & tod() const
const gamemap & map() const
const display & screen() const
config generate_report(const std::string &name, const context &ct, bool only_static=false)
void register_generator(const std::string &name, generator *)
std::set< std::string > all_reports_
const std::set< std::string > & report_list()
std::function< config(const reports::context &)> generator_function
dynamic_report_generators dynamic_generators_
std::string base_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 const 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
const std::string & flag_icon() const
int countdown_time() 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_string & income_description_own() const
int get_max_liminal_bonus() 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.
const std::vector< time_of_day > & times(const map_location &loc=map_location::null_location()) const
int get_current_time(const map_location &loc=map_location::null_location()) const
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
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.
static std::string _n(const char *str1, const char *str2, int n)
static std::string _(const char *str)
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.
bool invisible(const map_location &loc, bool see_all=true) const
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 defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
attack_itors attacks()
Gets an iterator over this unit's attacks.
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 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.
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.
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has.
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.
std::string id
Text to match against addon_info.tags()
symbol_table string_table
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
double get_battery_percentage()
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
const std::string weapon_details_sep
const color_t inactive_details_color
const color_t inactive_ability_color
std::string escape_text(const std::string &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
std::string span_color(const color_t &color)
Returns a Pango formatting string using the provided color_t object.
const color_t weapon_color
const std::string unicode_figure_dash
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....
Functions to load and save images from/to disk.
bool use_twelve_hour_clock_format()
std::set< t_translation::terrain_code > & encountered_terrains()
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(const std::string &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 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_attack_ptr sec_u_weapon=nullptr)
static config unit_type(const unit *u)
static std::string side_tooltip(const team &team)
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)
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_weapons(const reports::context &rc, unit_const_ptr attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
static void add_status(config &r, char const *path, char const *desc1, char const *desc2)
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 unit_abilities(const unit *u, const map_location &loc)
static config time_of_day_at(const reports::context &rc, const map_location &mouseover_hex)
#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 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.
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
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, 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