The Battle for Wesnoth  1.15.0-dev
reports.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "actions/attack.hpp"
16 #include "attack_prediction.hpp"
17 #include "desktop/battery_info.hpp"
18 #include "font/pango/escape.hpp"
19 #include "font/text_formatting.hpp"
20 #include "formatter.hpp"
21 #include "preferences/game.hpp"
22 #include "gettext.hpp"
23 #include "language.hpp"
24 #include "map/map.hpp"
25 #include "mouse_events.hpp"
26 #include "reports.hpp"
27 #include "color.hpp"
28 #include "team.hpp"
29 #include "terrain/movement.hpp"
30 #include "tod_manager.hpp"
31 #include "units/unit.hpp"
32 #include "units/helper.hpp"
33 #include "whiteboard/manager.hpp"
34 
35 #include <cassert>
36 #include <ctime>
37 #include <iomanip>
38 #include <boost/dynamic_bitset.hpp>
39 #include <boost/format.hpp>
40 #include <boost/lexical_cast.hpp>
41 
42 static void add_text(config &report, const std::string &text,
43  const std::string &tooltip, const std::string &help = "")
44 {
45  config &element = report.add_child("element");
46  element["text"] = text;
47  if (!tooltip.empty()) element["tooltip"] = tooltip;
48  if (!help.empty()) element["help"] = help;
49 }
50 
51 static void add_image(config &report, const std::string &image,
52  const std::string &tooltip, const std::string &help = "")
53 {
54  config &element = report.add_child("element");
55  element["image"] = image;
56  if (!tooltip.empty()) element["tooltip"] = tooltip;
57  if (!help.empty()) element["help"] = help;
58 }
59 
60 static config text_report(const std::string &text,
61  const std::string &tooltip = "", const std::string &help = "")
62 {
63  config r;
64  add_text(r, text, tooltip, help);
65  return r;
66 }
67 
68 static config image_report(const std::string &image,
69  const std::string &tooltip = "", const std::string &help = "")
70 {
71  config r;
72  add_image(r, image, tooltip, help);
73  return r;
74 }
75 
76 using font::span_color;
77 
78 static void add_status(config &r,
79  char const *path, char const *desc1, char const *desc2)
80 {
81  std::ostringstream s;
82  s << translation::gettext(desc1) << translation::gettext(desc2);
83  add_image(r, path, s.str());
84 }
85 
86 static std::string flush(std::ostringstream &s)
87 {
88  std::string r(s.str());
89  s.str(std::string());
90  return r;
91 }
92 
94 {
95  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
96  if (viewing_team.shrouded(hex)) {
97  // Don't show time on shrouded tiles.
98  return rc.tod().get_time_of_day();
99  } else if (viewing_team.fogged(hex)) {
100  // Don't show illuminated time on fogged tiles.
101  return rc.tod().get_time_of_day(hex);
102  } else {
103  return rc.tod().get_illuminated_time_of_day(rc.units(), rc.map(), hex);
104  }
105 }
106 
107 typedef std::map<std::string, reports::generator_function> static_report_generators;
109 
111 {
113  {
114  static_generators.insert(static_report_generators::value_type(name, g));
115  }
116 };
117 
118 #define REPORT_GENERATOR(n, cn) \
119  static config report_##n(reports::context & cn); \
120  static report_generator_helper reg_gen_##n(#n, &report_##n); \
121  static config report_##n(reports::context & cn)
122 
123 static char const *naps = "</span>";
124 
126 {
127  return rc.dc().get_visible_unit(rc.screen().displayed_unit_hex(),
128  rc.teams()[rc.screen().viewing_team()],
129  rc.screen().show_everything());
130 }
131 
133 {
134  return rc.dc().get_visible_unit(rc.screen().selected_hex(),
135  rc.teams()[rc.screen().viewing_team()],
136  rc.screen().show_everything());
137 }
138 
139 static config gray_inactive(reports::context & rc, const std::string &str, const std::string& tooltip = "")
140 {
141  if ( rc.screen().viewing_side() == rc.screen().playing_side() )
142  return text_report(str, tooltip);
143 
144  return text_report(span_color(font::GRAY_COLOR) + str + naps, tooltip);
145 }
146 
147 static config unit_name(const unit *u)
148 {
149  if (!u) {
150  return config();
151  }
152 
153  /*
154  * The name needs to be escaped, it might be set by the user and using
155  * markup. Also names often contain a forbidden single quote.
156  */
157  const std::string& name = font::escape_text(u->name());
158  std::ostringstream str, tooltip;
159  str << "<b>" << name << "</b>";
160  tooltip << _("Name: ") << "<b>" << name << "</b>";
161  return text_report(str.str(), tooltip.str());
162 }
163 
165 {
166  const unit *u = get_visible_unit(rc);
167  return unit_name(u);
168 }
169 REPORT_GENERATOR(selected_unit_name, rc)
170 {
171  const unit *u = get_selected_unit(rc);
172  return unit_name(u);
173 }
174 
175 static config unit_type(const unit* u)
176 {
177  if (!u) return config();
178  std::string has_variations_prefix = (u->type().show_variations_in_help() ? ".." : "");
179  std::ostringstream str, tooltip;
180  str << u->type_name();
181  tooltip << _("Type: ") << "<b>" << u->type_name() << "</b>\n"
182  << u->unit_description();
183  return text_report(str.str(), tooltip.str(), has_variations_prefix + "unit_" + u->type_id());
184 }
186 {
187  const unit *u = get_visible_unit(rc);
188  return unit_type(u);
189 }
190 REPORT_GENERATOR(selected_unit_type, rc)
191 {
192  const unit *u = get_selected_unit(rc);
193  return unit_type(u);
194 }
195 
196 static config unit_race(const unit* u)
197 {
198  if (!u) return config();
199  std::ostringstream str, tooltip;
200  str << u->race()->name(u->gender());
201  tooltip << _("Race: ") << "<b>" << u->race()->name(u->gender()) << "</b>";
202  return text_report(str.str(), tooltip.str(), "..race_" + u->race()->id());
203 }
205 {
206  const unit *u = get_visible_unit(rc);
207  return unit_race(u);
208 }
209 REPORT_GENERATOR(selected_unit_race, rc)
210 {
211  const unit *u = get_selected_unit(rc);
212  return unit_race(u);
213 }
214 
215 static config unit_side(reports::context & rc, const unit* u)
216 {
217  if (!u) return config();
218 
219  config report;
220  const team &u_team = rc.dc().get_team(u->side());
221  std::string flag_icon = u_team.flag_icon();
222  std::string old_rgb = game_config::flag_rgb;
223  std::string new_rgb = u_team.color();
224  std::string mods = "~RC(" + old_rgb + ">" + new_rgb + ")";
225  if (flag_icon.empty())
226  flag_icon = game_config::images::flag_icon;
227 
228  std::stringstream text;
229  text << " " << u->side();
230 
231  add_image(report, flag_icon + mods, u_team.side_name(), "");
232  add_text(report, text.str(), "", "");
233  return report;
234 }
236 {
237  const unit *u = get_visible_unit(rc);
238  return unit_side(rc,u);
239 }
240 REPORT_GENERATOR(selected_unit_side, rc)
241 {
242  const unit *u = get_selected_unit(rc);
243  return unit_side(rc, u);
244 }
245 
246 static config unit_level(const unit* u)
247 {
248  if (!u) return config();
249  std::ostringstream str, tooltip;
250  str << u->level();
251  tooltip << _("Level: ") << "<b>" << u->level() << "</b>\n";
252  const std::vector<std::string> &adv_to = u->advances_to_translated();
253  if (adv_to.empty())
254  tooltip << _("No advancement");
255  else
256  tooltip << _("Advances to:") << "\n<b>\t"
257  << utils::join(adv_to, "\n\t") << "</b>";
258  return text_report(str.str(), tooltip.str());
259 }
261 {
262  const unit *u = get_visible_unit(rc);
263  return unit_level(u);
264 }
265 REPORT_GENERATOR(selected_unit_level, rc)
266 {
267  const unit *u = get_selected_unit(rc);
268  return unit_level(u);
269 }
270 
271 REPORT_GENERATOR(unit_amla, rc)
272 {
273  const unit *u = get_visible_unit(rc);
274  if (!u) return config();
275  config res;
276  typedef std::pair<std::string, std::string> pair_string;
277  for (const pair_string &ps : u->amla_icons()) {
278  add_image(res, ps.first, ps.second);
279  }
280  return res;
281 }
282 
283 static config unit_traits(const unit* u)
284 {
285  if (!u) return config();
286  config res;
287  const std::vector<t_string> &traits = u->trait_names();
288  const std::vector<t_string> &descriptions = u->trait_descriptions();
289  const std::vector<std::string> &trait_ids = u->get_traits_list();
290  unsigned nb = traits.size();
291  for (unsigned i = 0; i < nb; ++i)
292  {
293  std::ostringstream str, tooltip;
294  str << traits[i];
295  if (i != nb - 1 ) str << ", ";
296  tooltip << _("Trait: ") << "<b>" << traits[i] << "</b>\n"
297  << descriptions[i];
298  add_text(res, str.str(), tooltip.str(), "traits_" + trait_ids[i]);
299  }
300  return res;
301 }
303 {
304  const unit *u = get_visible_unit(rc);
305  return unit_traits(u);
306 }
307 REPORT_GENERATOR(selected_unit_traits, rc)
308 {
309  const unit *u = get_selected_unit(rc);
310  return unit_traits(u);
311 }
312 
313 static config unit_status(reports::context & rc, const unit* u)
314 {
315  if (!u) return config();
316  config res;
317  map_location displayed_unit_hex = rc.screen().displayed_unit_hex();
318  if (rc.map().on_board(displayed_unit_hex) && u->invisible(displayed_unit_hex)) {
319  add_status(res, "misc/invisible.png", N_("invisible: "),
320  N_("This unit is invisible. It cannot be seen or attacked by enemy units."));
321  }
322  if (u->get_state(unit::STATE_SLOWED)) {
323  add_status(res, "misc/slowed.png", N_("slowed: "),
324  N_("This unit has been slowed. It will only deal half its normal damage when attacking and its movement cost is doubled."));
325  }
327  add_status(res, "misc/poisoned.png", N_("poisoned: "),
328  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."));
329  }
331  add_status(res, "misc/petrified.png", N_("petrified: "),
332  N_("This unit has been petrified. It may not move or attack."));
333  }
334  return res;
335 }
337 {
338  const unit *u = get_visible_unit(rc);
339  return unit_status(rc,u);
340 }
341 REPORT_GENERATOR(selected_unit_status, rc)
342 {
343  const unit *u = get_selected_unit(rc);
344  return unit_status(rc, u);
345 }
346 
347 static config unit_alignment(reports::context & rc, const unit* u, const map_location& hex)
348 {
349  if (!u) return config();
350  std::ostringstream str, tooltip;
351  const std::string align = unit_type::alignment_description(u->alignment(), u->gender());
352  const std::string align_id = u->alignment().to_string();
353  const time_of_day effective_tod = get_visible_time_of_day_at(rc, hex);
354  int cm = combat_modifier(effective_tod, u->alignment(), u->is_fearless());
355 
356  color_t color = font::weapon_color;
357  if (cm != 0)
358  color = (cm > 0) ? font::good_dmg_color : font::bad_dmg_color;
359 
360  str << align << " (" << span_color(color) << utils::signed_percent(cm)
361  << naps << ")";
362 
363  tooltip << _("Alignment: ") << "<b>" << align << "</b>\n"
364  << string_table[align_id + "_description"];
365 
366  return text_report(str.str(), tooltip.str(), "time_of_day");
367 }
369 {
370  const unit *u = get_visible_unit(rc);
371  const map_location& mouseover_hex = rc.screen().mouseover_hex();
372  const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
373  const map_location& hex = mouseover_hex.valid() ? mouseover_hex : displayed_unit_hex;
374  return unit_alignment(rc, u, hex);
375 }
376 REPORT_GENERATOR(selected_unit_alignment, rc)
377 {
378  const unit *u = get_selected_unit(rc);
379  const map_location& attack_indicator_src = game_display::get_singleton()->get_attack_indicator_src();
380  const map_location& hex_to_show_alignment_at =
381  attack_indicator_src.valid() ? attack_indicator_src : u->get_location();
382  return unit_alignment(rc, u, hex_to_show_alignment_at);
383 }
384 
385 
386 static config unit_abilities(const unit* u)
387 {
388  if (!u) return config();
389  config res;
390 
391  boost::dynamic_bitset<> active;
392  const std::vector<std::tuple<std::string, t_string,t_string,t_string>> &abilities = u->ability_tooltips(&active);
393  const std::size_t abilities_size = abilities.size();
394  for ( std::size_t i = 0; i != abilities_size; ++i )
395  {
396  // Aliases for readability:
397  const std::string& id = std::get<0>(abilities[i]);
398  const std::string& base_name = std::get<1>(abilities[i]).base_str();
399  const t_string& display_name = std::get<2>(abilities[i]);
400  const t_string& description = std::get<3>(abilities[i]);
401 
402  std::ostringstream str, tooltip;
403 
404  if ( active[i] )
405  str << display_name;
406  else
407  str << span_color(font::inactive_ability_color) << display_name << naps;
408  if ( i + 1 != abilities_size )
409  str << ", ";
410 
411  tooltip << _("Ability: ") << "<b>" << display_name << "</b>";
412  if ( !active[i] )
413  tooltip << "<i>" << _(" (inactive)") << "</i>";
414  tooltip << '\n' << description;
415 
416  add_text(res, str.str(), tooltip.str(), "ability_" + id + base_name);
417  }
418  return res;
419 }
421 {
422  const unit *u = get_visible_unit(rc);
423  return unit_abilities(u);
424 }
425 REPORT_GENERATOR(selected_unit_abilities, rc)
426 {
427  const unit *u = get_selected_unit(rc);
428  return unit_abilities(u);
429 }
430 
431 
432 static config unit_hp(reports::context& rc, const unit* u)
433 {
434  if (!u) return config();
435  std::ostringstream str, tooltip;
436  str << span_color(u->hp_color()) << u->hitpoints()
437  << '/' << u->max_hitpoints() << naps;
438 
439  std::set<std::string> resistances_table;
440 
441  bool att_def_diff = false;
442  map_location displayed_unit_hex = rc.screen().displayed_unit_hex();
443  for (const utils::string_map::value_type &resist : u->get_base_resistances())
444  {
445  std::ostringstream line;
446  line << translation::gettext(resist.first.c_str()) << ": ";
447  // Some units have different resistances when attacking or defending.
448  int res_att = 100 - u->resistance_against(resist.first, true, displayed_unit_hex);
449  int res_def = 100 - u->resistance_against(resist.first, false, displayed_unit_hex);
450  const std::string def_color = unit_helper::resistance_color(res_def);
451  if (res_att == res_def) {
452  line << "<span foreground=\"" << def_color << "\">" << utils::signed_percent(res_def)
453  << naps << '\n';
454  } else {
455  const std::string att_color = unit_helper::resistance_color(res_att);
456  line << "<span foreground=\"" << att_color << "\">" << utils::signed_percent(res_att)
457  << naps << "/"
458  << "<span foreground=\"" << def_color << "\">" << utils::signed_percent(res_def)
459  << naps << '\n';
460  att_def_diff = true;
461  }
462  resistances_table.insert(line.str());
463  }
464 
465  tooltip << _("Resistances: ");
466  if (att_def_diff)
467  tooltip << _("(Att / Def)");
468  tooltip << '\n';
469  for (const std::string &line : resistances_table) {
470  tooltip << line;
471  }
472  return text_report(str.str(), tooltip.str());
473 }
475 {
476  const unit *u = get_visible_unit(rc);
477  return unit_hp(rc, u);
478 }
479 REPORT_GENERATOR(selected_unit_hp, rc)
480 {
481  const unit *u = get_selected_unit(rc);
482  return unit_hp(rc, u);
483 }
484 
485 static config unit_xp(const unit* u)
486 {
487  if (!u) return config();
488  std::ostringstream str, tooltip;
489  str << span_color(u->xp_color());
490  if(u->can_advance()) {
491  str << u->experience() << '/' << u->max_experience();
492  } else {
493  str << font::unicode_en_dash;
494  }
495  str << naps;
496 
498  tooltip << _("Experience Modifier: ") << exp_mod << '%';
499  return text_report(str.str(), tooltip.str());
500 }
502 {
503  const unit *u = get_visible_unit(rc);
504  return unit_xp(u);
505 }
506 REPORT_GENERATOR(selected_unit_xp, rc)
507 {
508  const unit *u = get_selected_unit(rc);
509  return unit_xp(u);
510 }
511 
513 {
514  if (!u) return config();
515  config res;
516  typedef std::pair<std::string, std::string> pair_string;
517  for (const pair_string &ps : u->advancement_icons()) {
518  add_image(res, ps.first, ps.second);
519  }
520  return res;
521 }
523 {
524  const unit *u = get_visible_unit(rc);
525  return unit_advancement_options(u);
526 }
527 REPORT_GENERATOR(selected_unit_advancement_options, rc)
528 {
529  const unit *u = get_selected_unit(rc);
530  return unit_advancement_options(u);
531 }
532 
533 static config unit_defense(reports::context & rc, const unit* u, const map_location& displayed_unit_hex)
534 {
535  if(!u) {
536  return config();
537  }
538 
539  std::ostringstream str, tooltip;
540  const gamemap &map = rc.map();
541  if(!rc.map().on_board(displayed_unit_hex)) {
542  return config();
543  }
544 
545  const t_translation::terrain_code &terrain = map[displayed_unit_hex];
546  int def = 100 - u->defense_modifier(terrain);
547  color_t color = game_config::red_to_green(def);
548  str << span_color(color) << def << '%' << naps;
549  tooltip << _("Terrain: ") << "<b>" << map.get_terrain_info(terrain).description() << "</b>\n";
550 
551  const t_translation::ter_list &underlyings = map.underlying_def_terrain(terrain);
552  if (underlyings.size() != 1 || underlyings.front() != terrain)
553  {
554  bool revert = false;
555  for (const t_translation::terrain_code &t : underlyings)
556  {
557  if (t == t_translation::MINUS) {
558  revert = true;
559  } else if (t == t_translation::PLUS) {
560  revert = false;
561  } else {
562  int t_def = 100 - u->defense_modifier(t);
563  color_t t_color = game_config::red_to_green(t_def);
564  tooltip << '\t' << map.get_terrain_info(t).description() << ": "
565  << span_color(t_color) << t_def << '%' << naps
566  << (revert ? _("maximum^max.") : _("minimum^min.")) << '\n';
567  }
568  }
569  }
570 
571  tooltip << "<b>" << _("Defense: ") << span_color(color) << def << '%' << naps << "</b>";
572  return text_report(str.str(), tooltip.str());
573 }
575 {
576  const unit *u = get_visible_unit(rc);
577  const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
578  return unit_defense(rc, u, displayed_unit_hex);
579 }
580 REPORT_GENERATOR(selected_unit_defense, rc)
581 {
582  const unit *u = get_selected_unit(rc);
583  const map_location& selected_hex = rc.screen().selected_hex();
584  return unit_defense(rc, u, selected_hex);
585 }
586 
587 static config unit_vision(const unit* u)
588 {
589  if (!u) return config();
590 
591  // TODO
592  std::ostringstream str;
593  if (u->vision() != u->total_movement()) {
594  str << _("vision: ") << u->vision(); }
595  return text_report(str.str(), str.str());
596 }
598 {
599  const unit* u = get_visible_unit(rc);
600  return unit_vision(u);
601 }
602 REPORT_GENERATOR(selected_unit_vision, rc)
603 {
604  const unit* u = get_selected_unit(rc);
605  return unit_vision(u);
606 }
607 
608 static config unit_moves(reports::context & rc, const unit* u)
609 {
610  if (!u) return config();
611  std::ostringstream str, tooltip;
612  double movement_frac = 1.0;
613 
614  std::set<terrain_movement> terrain_moves;
615 
616  if (u->side() == rc.screen().playing_side()) {
617  movement_frac = static_cast<double>(u->movement_left()) / std::max<int>(1, u->total_movement());
618  if (movement_frac > 1.0)
619  movement_frac = 1.0;
620  }
621 
622  tooltip << _("Movement Costs:") << "\n";
625  continue;
626 
628 
629  if (info.union_type().size() == 1 && info.union_type()[0] == info.number() && info.is_nonnull()) {
630  terrain_moves.emplace(info.name(), u->movement_cost(terrain));
631  }
632  }
633 
634  for (const terrain_movement& tm : terrain_moves) {
635  tooltip << tm.name << ": ";
636 
637  std::string color;
638  //movement - range: 1 .. 5, movetype::UNREACHABLE=impassable
639  const bool cannot_move = tm.moves > u->total_movement();
640  if (cannot_move) // cannot move in this terrain
641  color = "red";
642  else if (tm.moves > 1)
643  color = "yellow";
644  else
645  color = "white";
646  tooltip << "<span foreground=\"" << color << "\">";
647  // A 5 MP margin; if the movement costs go above
648  // the unit's max moves + 5, we replace it with dashes.
649  if (cannot_move && (tm.moves > u->total_movement() + 5)) {
650  tooltip << font::unicode_figure_dash;
651  } else {
652  tooltip << tm.moves;
653  }
654  tooltip << naps << '\n';
655  }
656 
657  int grey = 128 + static_cast<int>((255 - 128) * movement_frac);
658  color_t c = color_t(grey, grey, grey);
659  str << span_color(c) << u->movement_left() << '/' << u->total_movement() << naps;
660  return text_report(str.str(), tooltip.str());
661 }
663 {
664  const unit *u = get_visible_unit(rc);
665  return unit_moves(rc, u);
666 }
667 REPORT_GENERATOR(selected_unit_moves, rc)
668 {
669  const unit *u = get_selected_unit(rc);
670  return unit_moves(rc, u);
671 }
672 
673 static inline const color_t attack_info_percent_color(int resistance)
674 {
675  // Compare unit_helper::resistance_color()
676  if (resistance < 0) return font::BAD_COLOR;
677  if (resistance > 0) return font::GOOD_COLOR;
678  return font::YELLOW_COLOR;
679 }
680 
681 static int attack_info(reports::context & rc, const attack_type &at, config &res, const unit &u, const map_location &hex)
682 {
683  std::ostringstream str, tooltip;
684  int damage = 0;
685 
686  {
687  auto ctx = at.specials_context(unit_const_ptr(&u), hex, u.side() == rc.screen().playing_side());
688  int base_damage = at.damage();
689  int specials_damage = at.modified_damage(false);
690  int damage_multiplier = 100;
691  const_attack_ptr weapon = at.shared_from_this();
692  int tod_bonus = combat_modifier(get_visible_time_of_day_at(rc, hex), u.alignment(), u.is_fearless());
693  damage_multiplier += tod_bonus;
694  int leader_bonus = under_leadership(u, hex, weapon);
695  if (leader_bonus != 0)
696  damage_multiplier += leader_bonus;
697 
699  int damage_divisor = slowed ? 20000 : 10000;
700  // Assume no specific resistance (i.e. multiply by 100).
701  damage = round_damage(specials_damage, damage_multiplier * 100, damage_divisor);
702 
703  // Hit points are used to calculate swarm, so they need to be bounded.
704  unsigned max_hp = u.max_hitpoints();
705  unsigned cur_hp = std::min<unsigned>(std::max(0, u.hitpoints()), max_hp);
706 
707  unsigned base_attacks = at.num_attacks();
708  unsigned min_attacks, max_attacks;
709  at.modified_attacks(false, min_attacks, max_attacks);
710  unsigned num_attacks = swarm_blows(min_attacks, max_attacks, cur_hp, max_hp);
711 
712  color_t dmg_color = font::weapon_color;
713  if ( damage > specials_damage )
714  dmg_color = font::good_dmg_color;
715  else if ( damage < specials_damage )
716  dmg_color = font::bad_dmg_color;
717 
718  str << span_color(dmg_color) << " " << damage << naps << span_color(font::weapon_color)
719  << font::weapon_numbers_sep << num_attacks << ' ' << at.name()
720  << "</span>\n";
721  tooltip << _("Weapon: ") << "<b>" << at.name() << "</b>\n"
722  << _("Damage: ") << "<b>" << damage << "</b>\n";
723 
724  if ( tod_bonus || leader_bonus || slowed || specials_damage != base_damage )
725  {
726  tooltip << '\t' << _("Base damage: ") << base_damage << '\n';
727  if ( specials_damage != base_damage ) {
728  tooltip << '\t' << _("With specials: ") << specials_damage << '\n';
729  }
730  if (tod_bonus) {
731  tooltip << '\t' << _("Time of day: ")
732  << utils::signed_percent(tod_bonus) << '\n';
733  }
734  if (leader_bonus) {
735  tooltip << '\t' << _("Leadership: ")
736  << utils::signed_percent(leader_bonus) << '\n';
737  }
738  if (slowed) {
739  tooltip << '\t' << _("Slowed: ") << "/ 2" << '\n';
740  }
741  }
742 
743  tooltip << _("Attacks: ") << "<b>" << num_attacks << "</b>\n";
744  if ( max_attacks != min_attacks && cur_hp != max_hp ) {
745  if ( max_attacks < min_attacks ) {
746  // "Reverse swarm"
747  tooltip << '\t' << _("Max swarm bonus: ") << (min_attacks-max_attacks) << '\n';
748  tooltip << '\t' << _("Swarm: ") << "* "<< (100 - cur_hp*100/max_hp) << "%\n";
749  tooltip << '\t' << _("Base attacks: ") << '+' << base_attacks << '\n';
750  // The specials line will not necessarily match up with how the
751  // specials are calculated, but for an unusual case, simple brevity
752  // trumps complexities.
753  if ( max_attacks != base_attacks ) {
754  int attack_diff = static_cast<int>(max_attacks) - static_cast<int>(base_attacks);
755  tooltip << '\t' << _("Specials: ") << utils::signed_value(attack_diff) << '\n';
756  }
757  }
758  else {
759  // Regular swarm
760  tooltip << '\t' << _("Base attacks: ") << base_attacks << '\n';
761  if ( max_attacks != base_attacks ) {
762  tooltip << '\t' << _("With specials: ") << max_attacks << '\n';
763  }
764  if ( min_attacks != 0 ) {
765  tooltip << '\t' << _("Subject to swarm: ") << (max_attacks-min_attacks) << '\n';
766  }
767  tooltip << '\t' << _("Swarm: ") << "* "<< (cur_hp*100/max_hp) << "%\n";
768  }
769  }
770  else if ( num_attacks != base_attacks ) {
771  tooltip << '\t' << _("Base attacks: ") << base_attacks << '\n';
772  tooltip << '\t' << _("With specials: ") << num_attacks << '\n';
773  }
774 
775  add_text(res, flush(str), flush(tooltip));
776 
777  std::string range = string_table["range_" + at.range()];
778  std::string lang_type = string_table["type_" + at.type()];
779 
780  str << span_color(font::weapon_details_color) << " " << " "
781  << range << font::weapon_details_sep
782  << lang_type << "</span>\n";
783 
784  tooltip << _("Weapon range: ") << "<b>" << range << "</b>\n"
785  << _("Damage type: ") << "<b>" << lang_type << "</b>\n"
786  << _("Damage versus: ") << '\n';
787 
788  // Show this weapon damage and resistance against all the different units.
789  // We want weak resistances (= good damage) first.
790  std::map<int, std::set<std::string>, std::greater<int>> resistances;
791  std::set<std::string> seen_types;
792  const team &unit_team = rc.dc().get_team(u.side());
793  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
794  for (const unit &enemy : rc.units())
795  {
796  if (enemy.incapacitated()) //we can't attack statues so don't display them in this tooltip
797  continue;
798  if (!unit_team.is_enemy(enemy.side()))
799  continue;
800  const map_location &loc = enemy.get_location();
801  if (viewing_team.fogged(loc) ||
802  (viewing_team.is_enemy(enemy.side()) && enemy.invisible(loc)))
803  continue;
804  bool new_type = seen_types.insert(enemy.type_id()).second;
805  if (new_type) {
806  int resistance = enemy.resistance_against(at, false, loc);
807  resistances[resistance].insert(enemy.type_name());
808  }
809  }
810 
811  typedef std::pair<int, std::set<std::string>> resist_units;
812  for (const resist_units &resist : resistances) {
813  int damage_with_resistance = round_damage(specials_damage, damage_multiplier * resist.first, damage_divisor);
814  tooltip << "<b>" << damage_with_resistance << "</b> "
815  << "<span color='" << attack_info_percent_color(resist.first-100).to_hex_string() << "'>"
816  << "<i>(" << utils::signed_percent(resist.first-100) << ")</i>"
817  << naps
818  << " : \t" // spaces to align the tab to a multiple of 8
819  << utils::join(resist.second, " " + font::unicode_bullet + " ") << '\n';
820  }
821  add_text(res, flush(str), flush(tooltip));
822 
823  const std::string &accuracy_parry = at.accuracy_parry_description();
824  if (!accuracy_parry.empty())
825  {
827  << " " << accuracy_parry << "</span>\n";
828  int accuracy = at.accuracy();
829  if (accuracy) {
830  tooltip << _("Accuracy:") << "<b>"
831  << utils::signed_percent(accuracy) << "</b>\n";
832  }
833  int parry = at.parry();
834  if (parry) {
835  tooltip << _("Parry:") << "<b>"
836  << utils::signed_percent(parry) << "</b>\n";
837  }
838  add_text(res, flush(str), flush(tooltip));
839  }
840  }
841 
842  {
843  auto ctx = at.specials_context_for_listing(u.side() == rc.screen().playing_side());
844  boost::dynamic_bitset<> active;
845  const std::vector<std::pair<t_string, t_string>> &specials = at.special_tooltips(&active);
846  const std::size_t specials_size = specials.size();
847  for ( std::size_t i = 0; i != specials_size; ++i )
848  {
849  // Aliases for readability:
850  const t_string &name = specials[i].first;
851  const t_string &description = specials[i].second;
852  const color_t &details_color = active[i] ? font::weapon_details_color :
854 
855  str << span_color(details_color) << " " << " " << name << naps << '\n';
856  std::string help_page = "weaponspecial_" + name.base_str();
857  tooltip << _("Weapon special: ") << "<b>" << name << "</b>";
858  if ( !active[i] )
859  tooltip << "<i>" << _(" (inactive)") << "</i>";
860  tooltip << '\n' << description;
861 
862  add_text(res, flush(str), flush(tooltip), help_page);
863  }
864  }
865  return damage;
866 }
867 
868 // Conversion routine for both unscathed and damage change percentage.
869 static std::string format_prob(double prob)
870 {
871  if(prob > 0.9995) {
872  return "100%";
873  } else if(prob < 0.0005) {
874  return "0%";
875  }
876  std::ostringstream res;
877  res << std::setprecision(prob < 0.1 ? 2 : 3) << 100.0 * prob << "%";
878  return res.str();
879 }
880 
881 static std::string format_hp(unsigned hp)
882 {
883  std::ostringstream res;
884  res << ' ' << std::setw(3) << hp;
885  return res.str();
886 }
887 
888 static config unit_weapons(reports::context & rc, const unit *attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
889 {
890  if (!attacker || !defender) return config();
891 
892  const unit* u = show_attacker ? attacker : defender;
893  const map_location unit_loc = show_attacker ? attacker_pos : defender->get_location();
894 
895  std::ostringstream str, tooltip;
896  config res;
897 
898  std::vector<battle_context> weapons;
899  for (unsigned int i = 0; i < attacker->attacks().size(); i++) {
900  // skip weapons with attack_weight=0
901  if (attacker->attacks()[i].attack_weight() > 0) {
902  weapons.emplace_back(rc.units(), attacker_pos, defender->get_location(), i, -1, 0.0, nullptr, attacker);
903  }
904  }
905 
906  for (const battle_context& weapon : weapons) {
907 
908  // Predict the battle outcome.
909  combatant attacker_combatant(weapon.get_attacker_stats());
910  combatant defender_combatant(weapon.get_defender_stats());
911  attacker_combatant.fight(defender_combatant);
912 
913  const battle_context_unit_stats& context_unit_stats =
914  show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
915 
916  int total_damage = 0;
917  int base_damage = 0;
918  int num_blows = 0;
919  int chance_to_hit = 0;
920  t_string weapon_name = _("weapon^None");
921 
922  color_t dmg_color = font::weapon_color;
923  if (context_unit_stats.weapon) {
924  base_damage = attack_info(rc, *context_unit_stats.weapon, res, *u, unit_loc);
925  total_damage = context_unit_stats.damage;
926  num_blows = context_unit_stats.num_blows;
927  chance_to_hit = context_unit_stats.chance_to_hit;
928  weapon_name = context_unit_stats.weapon->name();
929 
930  if ( total_damage > base_damage )
931  dmg_color = font::good_dmg_color;
932  else if ( total_damage < base_damage )
933  dmg_color = font::bad_dmg_color;
934  } else {
935  str << span_color(font::weapon_color) << weapon_name << naps << "\n";
936  tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
937  << _("Damage: ") << "<b>" << "0" << "</b>\n";
938  }
939 
940  color_t chance_color = game_config::red_to_green(chance_to_hit);
941 
942  // Total damage.
943  str << " " << span_color(dmg_color) << total_damage << naps << span_color(font::weapon_color)
944  << font::unicode_en_dash << num_blows
945  << " (" << span_color(chance_color) << chance_to_hit << "%" << naps << ")"
946  << naps << "\n";
947 
948  tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
949  << _("Total damage") << "<b>" << total_damage << "</b>\n";
950 
951  // Create the hitpoints distribution.
952  std::vector<std::pair<int, double>> hp_prob_vector;
953 
954  // First, we sort the probabilities in ascending order.
955  std::vector<std::pair<double, int>> prob_hp_vector;
956  int i;
957 
958  combatant* c = show_attacker ? &attacker_combatant : &defender_combatant;
959 
960  for(i = 0; i < static_cast<int>(c->hp_dist.size()); i++) {
961  double prob = c->hp_dist[i];
962 
963  // We keep only values above 0.1%.
964  if(prob > 0.001)
965  prob_hp_vector.emplace_back(prob, i);
966  }
967 
968  std::sort(prob_hp_vector.begin(), prob_hp_vector.end());
969 
970  //TODO fendrin -- make that dynamically
971  int max_hp_distrib_rows_ = 10;
972 
973  // We store a few of the highest probability hitpoint values.
974  int nb_elem = std::min<int>(max_hp_distrib_rows_, prob_hp_vector.size());
975 
976  for(i = prob_hp_vector.size() - nb_elem;
977  i < static_cast<int>(prob_hp_vector.size()); i++) {
978 
979  hp_prob_vector.emplace_back(prob_hp_vector[i].second, prob_hp_vector[i].first);
980  }
981 
982  // Then, we sort the hitpoint values in ascending order.
983  std::sort(hp_prob_vector.begin(), hp_prob_vector.end());
984  // And reverse the order. Might be doable in a better manor.
985  std::reverse(hp_prob_vector.begin(), hp_prob_vector.end());
986 
987  for(i = 0; i < static_cast<int>(hp_prob_vector.size()); i++) {
988 
989  int hp = hp_prob_vector[i].first;
990  double prob = hp_prob_vector[i].second;
991  color_t prob_color = game_config::blue_to_white(prob * 100.0, true);
992 
993  str << span_color(font::weapon_details_color) << " " << " "
994  << span_color(u->hp_color(hp)) << format_hp(hp) << naps
995  << " " << font::weapon_numbers_sep << " "
996  << span_color(prob_color) << format_prob(prob) << naps
997  << naps << "\n";
998  }
999 
1000  add_text(res, flush(str), flush(tooltip));
1001  }
1002  return res;
1003 }
1004 
1005 /*
1006  * Display the attacks of the displayed unit against the unit passed as argument.
1007  * 'hex' is the location the attacker will be at during combat.
1008  */
1009 static config unit_weapons(reports::context & rc, const unit *u, const map_location &hex)
1010 {
1011  config res = config();
1012  if ((u != nullptr) && (!u->attacks().empty())) {
1013  const std::string attack_headline = _n("Attack", "Attacks", u->attacks().size());
1014 
1016  + attack_headline + "</span>" + '\n', "");
1017 
1018  for (const attack_type &at : u->attacks())
1019  {
1020  attack_info(rc, at, res, *u, hex);
1021  }
1022  }
1023  return res;
1024 }
1026 {
1027  const unit *u = get_visible_unit(rc);
1028  const map_location& mouseover_hex = rc.screen().mouseover_hex();
1029  const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
1030  const map_location& hex = mouseover_hex.valid() ? mouseover_hex : displayed_unit_hex;
1031  if (!u) return config();
1032 
1033  return unit_weapons(rc, u, hex);
1034 }
1035 REPORT_GENERATOR(highlighted_unit_weapons, rc)
1036 {
1037  const unit *u = get_selected_unit(rc);
1038  const unit *sec_u = get_visible_unit(rc);
1039 
1040  if (!u) return config();
1041  if (!sec_u || u == sec_u) return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1042 
1043  map_location highlighted_hex = rc.screen().displayed_unit_hex();
1044  map_location attack_loc;
1045  if (rc.mhb())
1046  attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1047 
1048  if (!attack_loc.valid())
1049  return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1050 
1051  return unit_weapons(rc, u, attack_loc, sec_u, false);
1052 }
1053 REPORT_GENERATOR(selected_unit_weapons, rc)
1054 {
1055  const unit *u = get_selected_unit(rc);
1056  const unit *sec_u = get_visible_unit(rc);
1057 
1058  if (!u) return config();
1059  if (!sec_u || u == sec_u) return unit_weapons(rc, u, u->get_location());
1060 
1061  map_location highlighted_hex = rc.screen().displayed_unit_hex();
1062  map_location attack_loc;
1063  if (rc.mhb())
1064  attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1065 
1066  if (!attack_loc.valid())
1067  return unit_weapons(rc, u, u->get_location());
1068 
1069  return unit_weapons(rc, u, attack_loc, sec_u, true);
1070 }
1071 
1072 REPORT_GENERATOR(unit_image,rc)
1073 {
1074  const unit *u = get_visible_unit(rc);
1075  if (!u) return config();
1076  return image_report(u->absolute_image() + u->image_mods());
1077 }
1078 REPORT_GENERATOR(selected_unit_image, rc)
1079 {
1080  const unit *u = get_selected_unit(rc);
1081  if (!u) return config();
1082  return image_report(u->absolute_image() + u->image_mods());
1083 }
1084 
1085 REPORT_GENERATOR(selected_unit_profile, rc)
1086 {
1087  const unit *u = get_selected_unit(rc);
1088  if (!u) return config();
1089  return image_report(u->small_profile());
1090 }
1091 REPORT_GENERATOR(unit_profile, rc)
1092 {
1093  const unit *u = get_visible_unit(rc);
1094  if (!u) return config();
1095  return image_report(u->small_profile());
1096 }
1097 
1098 REPORT_GENERATOR(tod_stats, rc)
1099 {
1100  std::ostringstream tooltip;
1101  std::ostringstream text;
1102 
1103  const map_location& selected_hex = rc.screen().selected_hex();
1104  const map_location& mouseover_hex = rc.screen().mouseover_hex();
1105 
1106  const map_location& hex = mouseover_hex.valid() ? mouseover_hex : selected_hex;
1107 
1108  const map_location& tod_schedule_hex = display::get_singleton()->shrouded(hex) ? map_location::null_location() : hex;
1109  const std::vector<time_of_day>& schedule = rc.tod().times(tod_schedule_hex);
1110 
1111  int current = rc.tod().get_current_time(tod_schedule_hex);
1112  int i = 0;
1113  for (const time_of_day& tod : schedule) {
1114  if (i == current) tooltip << "<big><b>";
1115  tooltip << tod.name << "\n";
1116  if (i == current) tooltip << "</b></big>";
1117  i++;
1118  }
1119 
1120  int times = schedule.size();
1121  text << current + 1 << "/" << times;
1122 
1123  return text_report(text.str(), tooltip.str(), "..schedule");
1124 }
1125 
1126 static config time_of_day_at(reports::context & rc, const map_location& mouseover_hex)
1127 {
1128  std::ostringstream tooltip;
1129  time_of_day tod = get_visible_time_of_day_at(rc, mouseover_hex);
1130 
1131  int b = tod.lawful_bonus;
1132 
1133  std::string lawful_color("white");
1134  std::string chaotic_color("white");
1135  std::string liminal_color("white");
1136 
1137  if (b != 0) {
1138  lawful_color = (b > 0) ? "green" : "red";
1139  chaotic_color = (b < 0) ? "green" : "red";
1140  liminal_color = "red";
1141  }
1142  tooltip << tod.name << '\n'
1143  << _("Lawful units: ") << "<span foreground=\"" << lawful_color << "\">"
1144  << utils::signed_percent(b) << "</span>\n"
1145  << _("Neutral units: ") << utils::signed_percent(0) << '\n'
1146  << _("Chaotic units: ") << "<span foreground=\"" << chaotic_color << "\">"
1147  << utils::signed_percent(-b) << "</span>\n"
1148  << _("Liminal units: ") << "<span foreground=\"" << liminal_color << "\">"
1149  << utils::signed_percent(-(std::abs(b))) << "</span>\n";
1150 
1151  std::string tod_image = tod.image;
1152  if(tod.bonus_modified > 0) {
1153  tod_image += (formatter() << "~BLIT(" << game_config::images::tod_bright << ")").str();
1154  } else if(tod.bonus_modified < 0) {
1155  tod_image += (formatter() << "~BLIT(" << game_config::images::tod_dark << ")").str();
1156  }
1157 
1158  return image_report(tod_image, tooltip.str(), "time_of_day_" + tod.id);
1159 }
1161 {
1162  map_location mouseover_hex = rc.screen().mouseover_hex();
1163  if (mouseover_hex.valid()) return time_of_day_at(rc, mouseover_hex);
1164  return time_of_day_at(rc, rc.screen().selected_hex());
1165 }
1166 
1167 static config unit_box_at(reports::context & rc, const map_location& mouseover_hex)
1168 {
1169  std::ostringstream tooltip;
1170  time_of_day global_tod = rc.tod().get_time_of_day();
1171  time_of_day local_tod = get_visible_time_of_day_at(rc, mouseover_hex);
1172 
1173  int bonus = local_tod.lawful_bonus;
1174 
1175  std::string lawful_color("white");
1176  std::string chaotic_color("white");
1177  std::string liminal_color("white");
1178 
1179  if (bonus != 0) {
1180  lawful_color = (bonus > 0) ? "green" : "red";
1181  chaotic_color = (bonus < 0) ? "green" : "red";
1182  liminal_color = "red";
1183  }
1184  tooltip << local_tod.name << '\n'
1185  << _("Lawful units: ") << "<span foreground=\"" << lawful_color << "\">"
1186  << utils::signed_percent(bonus) << "</span>\n"
1187  << _("Neutral units: ") << utils::signed_percent(0) << '\n'
1188  << _("Chaotic units: ") << "<span foreground=\"" << chaotic_color << "\">"
1189  << utils::signed_percent(-bonus) << "</span>\n"
1190  << _("Liminal units: ") << "<span foreground=\"" << liminal_color << "\">"
1191  << utils::signed_percent(-(std::abs(bonus))) << "</span>\n";
1192 
1193  std::string local_tod_image = "themes/classic/" + local_tod.image;
1194  std::string global_tod_image = "themes/classic/" + global_tod.image;
1195  if(local_tod.bonus_modified != 0) {
1196  local_tod_image += "~BLIT(";
1197  if (local_tod.bonus_modified > 0) local_tod_image += game_config::images::tod_bright;
1198  else if (local_tod.bonus_modified < 0) local_tod_image += game_config::images::tod_dark;
1199  local_tod_image += ")";
1200  }
1201 
1202  const gamemap &map = rc.map();
1203  t_translation::terrain_code terrain = map.get_terrain(mouseover_hex);
1204 
1205  //if (t_translation::terrain_matches(terrain, t_translation::ALL_OFF_MAP))
1206  // return config();
1207 
1208  //if (map.is_keep(mouseover_hex)) {
1209  // add_image(cfg, "icons/terrain/terrain_type_keep.png", "");
1210  //}
1211 
1212  const t_translation::ter_list& underlying_terrains = map.underlying_union_terrain(terrain);
1213 
1214  std::string bg_terrain_image;
1215 
1216  for (const t_translation::terrain_code& underlying_terrain : underlying_terrains) {
1217  const std::string& terrain_id = map.get_terrain_info(underlying_terrain).id();
1218  bg_terrain_image = "~BLIT(unit_env/terrain/terrain-" + terrain_id + ".png)" + bg_terrain_image;
1219  }
1220 
1221  std::stringstream color;
1222  color << local_tod.color;
1223 
1224  bg_terrain_image = bg_terrain_image + "~CS(" + color.str() + ")";
1225 
1226  const unit *u = get_visible_unit(rc);
1227  std::string unit_image;
1228  if (u)
1229  unit_image = "~BLIT(" + u->absolute_image() + u->image_mods() + ",35,22)";
1230 
1231  std::string tod_image = global_tod_image + "~BLIT(" + local_tod_image + ")";
1232 
1233  return image_report(tod_image + bg_terrain_image + unit_image, tooltip.str(), "time_of_day");
1234 }
1235 REPORT_GENERATOR(unit_box, rc)
1236 {
1237  map_location mouseover_hex = rc.screen().mouseover_hex();
1238  return unit_box_at(rc, mouseover_hex);
1239 }
1240 
1241 
1243 {
1244  std::ostringstream str, tooltip;
1245  str << rc.tod().turn();
1246  int nb = rc.tod().number_of_turns();
1247  if (nb != -1) str << '/' << nb;
1248 
1249  tooltip << _("Turn Number");
1250  if(nb != -1) {
1251  tooltip << "\n\n" << _("When the game reaches the number of turns indicated by the second number, it will end.");
1252  }
1253  return text_report(str.str(), tooltip.str());
1254 }
1255 
1257 {
1258  std::ostringstream str;
1259  int viewing_side = rc.screen().viewing_side();
1260  // Suppose the full unit map is applied.
1261  int fake_gold = rc.dc().get_team(viewing_side).gold();
1262 
1263  if (rc.wb())
1264  fake_gold -= rc.wb()->get_spent_gold_for(viewing_side);
1265  char const *end = naps;
1266  if (viewing_side != rc.screen().playing_side()) {
1267  str << span_color(font::GRAY_COLOR);
1268  }
1269  else if (fake_gold < 0) {
1270  str << span_color(font::BAD_COLOR);
1271  }
1272  else {
1273  end = "";
1274  }
1275  str << utils::half_signed_value(fake_gold) << end;
1276  return text_report(str.str(), _("Gold") + "\n\n" + _("The amount of gold currently available to recruit and maintain your army."));
1277 }
1278 
1279 REPORT_GENERATOR(villages, rc)
1280 {
1281  std::ostringstream str;
1282  int viewing_side = rc.screen().viewing_side();
1283  const team &viewing_team = rc.dc().get_team(viewing_side);
1284  str << viewing_team.villages().size() << '/';
1285  if (viewing_team.uses_shroud()) {
1286  int unshrouded_villages = 0;
1287  for (const map_location &loc : rc.map().villages()) {
1288  if (!viewing_team.shrouded(loc))
1289  ++unshrouded_villages;
1290  }
1291  str << unshrouded_villages;
1292  } else {
1293  str << rc.map().villages().size();
1294  }
1295  return gray_inactive(rc,str.str(), _("Villages") + "\n\n" + _("The fraction of known villages that your side has captured."));
1296 }
1297 
1298 REPORT_GENERATOR(num_units, rc)
1299 {
1300  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."));
1301 }
1302 
1303 REPORT_GENERATOR(upkeep, rc)
1304 {
1305  std::ostringstream str;
1306  int viewing_side = rc.screen().viewing_side();
1307  const team &viewing_team = rc.dc().get_team(viewing_side);
1308  team_data td = rc.dc().calculate_team_data(viewing_team);
1309  str << td.expenses << " (" << td.upkeep << ")";
1310  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. 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."));
1311 }
1312 
1313 REPORT_GENERATOR(expenses, rc)
1314 {
1315  int viewing_side = rc.screen().viewing_side();
1316  const team &viewing_team = rc.dc().get_team(viewing_side);
1317  team_data td = rc.dc().calculate_team_data(viewing_team);
1318  return gray_inactive(rc,std::to_string(td.expenses));
1319 }
1320 
1321 REPORT_GENERATOR(income, rc)
1322 {
1323  std::ostringstream str;
1324  int viewing_side = rc.screen().viewing_side();
1325  const team &viewing_team = rc.dc().get_team(viewing_side);
1326  team_data td = rc.dc().calculate_team_data(viewing_team);
1327  char const *end = naps;
1328  if (viewing_side != rc.screen().playing_side()) {
1329  if (td.net_income < 0) {
1330  td.net_income = - td.net_income;
1331  str << span_color(font::GRAY_COLOR);
1332  str << font::unicode_minus;
1333  }
1334  else {
1335  str << span_color(font::GRAY_COLOR);
1336  }
1337  }
1338  else if (td.net_income < 0) {
1339  td.net_income = - td.net_income;
1340  str << span_color(font::BAD_COLOR);
1341  str << font::unicode_minus;
1342  }
1343  else {
1344  end = "";
1345  }
1346  str << td.net_income << end;
1347  return text_report(str.str(), _("Income") + "\n\n" + _("The amount of gold you gain each turn from your controlled villages, or the amount of gold you will lose each turn for unit upkeep."));
1348 }
1349 
1350 namespace {
1351 void blit_tced_icon(config &cfg, const std::string &terrain_id, const std::string &icon_image, bool high_res,
1352  const std::string &terrain_name) {
1353  const std::string tc_base = high_res ? "images/buttons/icon-base-32.png" : "images/buttons/icon-base-16.png";
1354  const std::string terrain_image = "terrain/" + icon_image + (high_res ? "_30.png" : ".png");
1355  add_image(cfg, tc_base + "~RC(magenta>" + terrain_id + ")~BLIT(" + terrain_image + ")", terrain_name);
1356 }
1357 }
1358 
1359 REPORT_GENERATOR(terrain_info, rc)
1360 {
1361  const gamemap &map = rc.map();
1362  map_location mouseover_hex = rc.screen().mouseover_hex();
1363 
1364  if (!map.on_board(mouseover_hex))
1365  mouseover_hex = rc.screen().selected_hex();
1366 
1367  if (!map.on_board(mouseover_hex))
1368  return config();
1369 
1370  t_translation::terrain_code terrain = map.get_terrain(mouseover_hex);
1372  return config();
1373 
1374  config cfg;
1375 
1376  bool high_res = false;
1377 
1378  if (display::get_singleton()->shrouded(mouseover_hex)) {
1379  return cfg;
1380  }
1381  //TODO
1382 // if (display::get_singleton()->fogged(mouseover_hex)) {
1383 // blit_tced_icon(cfg, "fog", high_res);
1384 // }
1385 //
1386 // if (map.is_keep(mouseover_hex)) {
1387 // blit_tced_icon(cfg, "keep", high_res);
1388 // }
1389 
1390  const t_translation::ter_list& underlying_terrains = map.underlying_union_terrain(terrain);
1391  for (const t_translation::terrain_code& underlying_terrain : underlying_terrains) {
1392 
1394  continue;
1395  const std::string& terrain_id = map.get_terrain_info(underlying_terrain).id();
1396  const std::string& terrain_name = map.get_terrain_string(underlying_terrain);
1397  const std::string& terrain_icon = map.get_terrain_info(underlying_terrain).icon_image();
1398  if (terrain_icon.empty())
1399  continue;
1400  blit_tced_icon(cfg, terrain_id, terrain_icon, high_res, terrain_name);
1401  }
1402  return cfg;
1403 }
1404 
1406 {
1407  const gamemap &map = rc.map();
1408  int viewing_side = rc.screen().viewing_side();
1409  const team &viewing_team = rc.dc().get_team(viewing_side);
1410  map_location mouseover_hex = rc.screen().mouseover_hex();
1411  if (!map.on_board(mouseover_hex) || viewing_team.shrouded(mouseover_hex))
1412  return config();
1413 
1414  t_translation::terrain_code terrain = map.get_terrain(mouseover_hex);
1416  return config();
1417 
1418  std::ostringstream str;
1419  if (map.is_village(mouseover_hex))
1420  {
1421  int owner = rc.dc().village_owner(mouseover_hex) + 1;
1422  if (owner == 0 || viewing_team.fogged(mouseover_hex)) {
1423  str << map.get_terrain_info(terrain).income_description();
1424  } else if (owner == viewing_side) {
1425  str << map.get_terrain_info(terrain).income_description_own();
1426  } else if (viewing_team.is_enemy(owner)) {
1427  str << map.get_terrain_info(terrain).income_description_enemy();
1428  } else {
1429  str << map.get_terrain_info(terrain).income_description_ally();
1430  }
1431 
1432  const std::string& underlying_desc = map.get_underlying_terrain_string(terrain);
1433  if(!underlying_desc.empty()) {
1434  str << underlying_desc;
1435  }
1436  } else {
1437  str << map.get_terrain_string(terrain);
1438  }
1439 
1440  return text_report(str.str());
1441 }
1442 
1443 REPORT_GENERATOR(zoom_level, rc)
1444 {
1445  std::ostringstream text;
1446  std::ostringstream tooltip;
1447  std::ostringstream help;
1448 
1449  text << static_cast<int>(rc.screen().get_zoom_factor() * 100) << "%";
1450 
1451  return text_report(text.str(), tooltip.str(), help.str());
1452 }
1453 
1454 REPORT_GENERATOR(position, rc)
1455 {
1456  const gamemap &map = rc.map();
1457  map_location mouseover_hex = rc.screen().mouseover_hex(),
1458  displayed_unit_hex = rc.screen().displayed_unit_hex(),
1459  selected_hex = rc.screen().selected_hex();
1460 
1461  if (!map.on_board(mouseover_hex)) {
1462  if (!map.on_board(selected_hex))
1463  return config();
1464  else {
1465  mouseover_hex = selected_hex;
1466  }
1467  }
1468 
1469  t_translation::terrain_code terrain = map[mouseover_hex];
1471  return config();
1472 
1473  std::ostringstream str;
1474  str << mouseover_hex;
1475 
1476  const unit *u = get_visible_unit(rc);
1477  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1478  if (!u ||
1479  (displayed_unit_hex != mouseover_hex &&
1480  displayed_unit_hex != rc.screen().selected_hex()) ||
1481  viewing_team.shrouded(mouseover_hex))
1482  return text_report(str.str());
1483 
1484  int move_cost = u->movement_cost(terrain);
1485  int defense = 100 - u->defense_modifier(terrain);
1486  if (move_cost < movetype::UNREACHABLE) {
1487  str << " " << defense << "%," << move_cost;
1488  } else if (mouseover_hex == displayed_unit_hex) {
1489  str << " " << defense << "%,‒";
1490  } else {
1491  str << " ‒";
1492  }
1493  return text_report(str.str());
1494 }
1495 
1496 REPORT_GENERATOR(side_playing, rc)
1497 {
1498  const team &active_team = rc.teams()[rc.screen().playing_team()];
1499  std::string flag_icon = active_team.flag_icon();
1500  std::string old_rgb = game_config::flag_rgb;
1501  std::string new_rgb = team::get_side_color_id(rc.screen().playing_side());
1502  std::string mods = "~RC(" + old_rgb + ">" + new_rgb + ")";
1503  if (flag_icon.empty())
1504  flag_icon = game_config::images::flag_icon;
1505  return image_report(flag_icon + mods, active_team.side_name());
1506 }
1507 
1508 REPORT_GENERATOR(observers, rc)
1509 {
1510  const std::set<std::string> &observers = rc.screen().observers();
1511  if (observers.empty())
1512  return config();
1513 
1514  std::ostringstream str;
1515  str << _("Observers:") << '\n';
1516  for (const std::string &obs : observers) {
1517  str << obs << '\n';
1518  }
1519  return image_report(game_config::images::observer, str.str());
1520 }
1521 
1522 /* TODO unused
1523 REPORT_GENERATOR(selected_terrain)
1524 {
1525  const std::string selected_terrain = editor::get_selected_terrain();
1526  if (selected_terrain.empty())
1527  return config();
1528  else
1529  return text_report(selected_terrain);
1530 }
1531 */
1532 
1533 /* TODO this is unused
1534 REPORT_GENERATOR(edit_left_button_function)
1535 {
1536  const std::string left_button_function = editor::get_left_button_function();
1537  if (left_button_function.empty())
1538  return config();
1539  else
1540  return text_report(left_button_function);
1541 }
1542 */
1543 
1544 REPORT_GENERATOR(report_clock, /*rc*/)
1545 {
1546  config report;
1548 
1549  std::ostringstream ss;
1550 
1552  ? "%I:%M %p"
1553  : "%H:%M";
1554 
1555  std::time_t t = std::time(nullptr);
1556  ss << std::put_time(std::localtime(&t), format);
1557  add_text(report, ss.str(), _("Clock"));
1558 
1559  return report;
1560 }
1561 
1562 
1563 REPORT_GENERATOR(battery, /*rc*/)
1564 {
1565  config report;
1566 
1569  add_text(report, (boost::format("%.0f %%") % desktop::battery_info::get_battery_percentage()).str(), _("Battery"));
1570  }
1571 
1572  return report;
1573 }
1574 
1575 REPORT_GENERATOR(report_countdown, rc)
1576 {
1577  int viewing_side = rc.screen().viewing_side();
1578  const team &viewing_team = rc.dc().get_team(viewing_side);
1579  int min, sec;
1580  if (viewing_team.countdown_time() == 0)
1581  return report_report_clock(rc);
1582  std::ostringstream str;
1583  sec = viewing_team.countdown_time() / 1000;
1584  char const *end = naps;
1585  if (viewing_side != rc.screen().playing_side())
1586  str << span_color(font::GRAY_COLOR);
1587  else if (sec < 60)
1588  str << "<span foreground=\"#c80000\">";
1589  else if (sec < 120)
1590  str << "<span foreground=\"#c8c800\">";
1591  else
1592  end = "";
1593  min = sec / 60;
1594  str << min << ':';
1595  sec = sec % 60;
1596  if (sec < 10) str << '0';
1597  str << sec << end;
1598  return text_report(str.str(), _("Turn Countdown") + "\n\n" + _("Countdown until your turn automatically ends."));
1599 }
1600 
1602 {
1603  dynamic_generators_[name].reset(g);
1604 }
1605 
1606 config reports::generate_report(const std::string &name, reports::context & rc, bool only_static)
1607 {
1608  if (!only_static) {
1609  dynamic_report_generators::const_iterator i = dynamic_generators_.find(name);
1610  if (i != dynamic_generators_.end())
1611  return i->second->generate(rc);
1612  }
1613  static_report_generators::const_iterator j = static_generators.find(name);
1614  if (j != static_generators.end())
1615  return j->second(rc);
1616  return config();
1617 }
1618 
1619 const std::set<std::string> &reports::report_list()
1620 {
1621  if (!all_reports_.empty()) return all_reports_;
1622  for (const static_report_generators::value_type &v : static_generators) {
1623  all_reports_.insert(v.first);
1624  }
1625  for (const dynamic_report_generators::value_type &v : dynamic_generators_) {
1626  all_reports_.insert(v.first);
1627  }
1628  return all_reports_;
1629 }
const_attack_ptr weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
Definition: attack.hpp:50
static config unit_level(const unit *u)
Definition: reports.cpp:246
boost::intrusive_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:30
const gamemap & map() const
Definition: reports.hpp:52
std::string battery_icon
static config unit_xp(const unit *u)
Definition: reports.cpp:485
const t_translation::ter_list & underlying_union_terrain(const map_location &loc) const
Definition: map.cpp:58
std::string tod_dark
const t_translation::ter_list & underlying_def_terrain(const map_location &loc) const
Definition: map.cpp:56
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
int countdown_time() const
Definition: team.hpp:210
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:88
static int get_acceleration()
Definition: types.cpp:523
virtual const map_location & displayed_unit_hex() const
Virtual functions shadowed in game_display.
Definition: display.hpp:205
const team & get_team(int side) const
const t_string & description() const
Definition: terrain.hpp:35
int vision() const
Gets the unit&#39;s vision points.
Definition: unit.hpp:1299
const std::string weapon_details_sep
Definition: constants.cpp:46
This class represents a single unit of a specific type.
Definition: unit.hpp:99
const color_t inactive_details_color
const std::vector< team > & teams() const
Definition: reports.hpp:50
static config time_of_day_at(reports::context &rc, const map_location &mouseover_hex)
Definition: reports.cpp:1126
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&#39;s movement cost on a particular terrain.
Definition: unit.hpp:1339
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
const color_t GRAY_COLOR
const unit * get_visible_unit(const map_location &loc, const team &current_team, bool see_all=false) const
static config unit_advancement_options(const unit *u)
Definition: reports.cpp:512
std::string get_underlying_terrain_string(const t_translation::terrain_code &terrain) const
Definition: map.cpp:86
const map_location & selected_hex() const
Definition: display.hpp:284
Various functions that implement attacks and attack calculations.
const std::string & id() const
Definition: race.hpp:34
static char const * naps
Definition: reports.cpp:123
const std::string & side_name() const
Definition: team.hpp:306
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1310
const color_t GOOD_COLOR
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.
Definition: unit.hpp:419
color_t blue_to_white(int val, bool for_text)
const map_location & get_attack_indicator_src()
logger & info()
Definition: log.cpp:90
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
Definition: movetype.hpp:83
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:453
static void add_status(config &r, char const *path, char const *desc1, char const *desc2)
Definition: reports.cpp:78
std::string id
Definition: time_of_day.hpp:91
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.
Definition: attack.cpp:1567
static config image_report(const std::string &image, const std::string &tooltip="", const std::string &help="")
Definition: reports.cpp:68
bool show_everything() const
Definition: display.hpp:90
const std::set< std::string > & report_list()
Definition: reports.cpp:1619
static std::string format_hp(unsigned hp)
Definition: reports.cpp:881
int lawful_bonus
The % bonus lawful units receive.
Definition: time_of_day.hpp:84
const color_t good_dmg_color
int parry() const
Definition: attack_type.hpp:49
void modified_attacks(bool is_backstab, unsigned &min_attacks, unsigned &max_attacks) const
Calculates the number of attacks this weapon has, considering specials.
Definition: abilities.cpp:820
The unit is poisoned - it loses health each turn.
Definition: unit.hpp:810
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:50
static config text_report(const std::string &text, const std::string &tooltip="", const std::string &help="")
Definition: reports.cpp:60
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:97
int viewing_side() const
Definition: display.hpp:103
std::string image
The image to be displayed in the game status.
Definition: time_of_day.hpp:88
static std::string format_prob(double prob)
Definition: reports.cpp:869
The unit is petrified - it cannot move or be attacked.
Definition: unit.hpp:811
std::string absolute_image() const
The name of the file to game_display (used in menus).
Definition: unit.cpp:2353
const std::string & type() const
Definition: attack_type.hpp:42
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:377
const t_string & income_description() const
Definition: terrain.hpp:71
const std::string & type_id() const
The id of this unit&#39;s type.
Definition: unit.hpp:326
static config unit_side(reports::context &rc, const unit *u)
Definition: reports.cpp:215
static config unit_name(const unit *u)
Definition: reports.cpp:147
const tod_manager & tod() const
Definition: reports.hpp:56
static config unit_traits(const unit *u)
Definition: reports.cpp:283
report_generator_helper(const char *name, reports::generator_function g)
Definition: reports.cpp:112
static config unit_type(const unit *u)
Definition: reports.cpp:175
static const color_t attack_info_percent_color(int resistance)
Definition: reports.cpp:673
-file sdl_utils.hpp
utils::string_map get_base_resistances() const
Gets resistances without any abilities applied.
Definition: unit.hpp:992
display & screen()
Definition: reports.hpp:55
int num_attacks() const
Definition: attack_type.hpp:51
unit_type::ALIGNMENT alignment() const
The alignment of this unit.
Definition: unit.hpp:429
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
Definition: attack.hpp:73
A single unit type that the player may recruit.
Definition: types.hpp:42
bool is_nonnull() const
Definition: terrain.hpp:52
std::string get_terrain_string(const map_location &loc) const
Definition: map.cpp:60
const t_string & name(GENDER gender=MALE) const
Definition: race.hpp:36
static config gray_inactive(reports::context &rc, const std::string &str, const std::string &tooltip="")
Definition: reports.cpp:139
t_translation::terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:309
const terrain_code VOID_TERRAIN
std::string flag_icon
const color_t weapon_color
#define b
const unit_type & type() const
This unit&#39;s type, accounting for gender and variation.
Definition: unit.hpp:315
static static_report_generators static_generators
Definition: reports.cpp:108
color_t hp_color() const
Color for this unit&#39;s current hitpoints.
Definition: unit.cpp:1091
t_string name
Definition: time_of_day.hpp:89
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:57
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
static config unit_race(const unit *u)
Definition: reports.cpp:196
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit&#39;s defense on a given terrain.
Definition: unit.cpp:1596
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 &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
static std::string at(const std::string &file, int line)
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
const color_t bad_dmg_color
int damage
Effective damage of the weapon (all factors accounted for).
Definition: attack.hpp:74
const std::string unicode_minus
Definition: constants.cpp:38
static config unit_alignment(reports::context &rc, const unit *u, const map_location &hex)
Definition: reports.cpp:347
bool uses_shroud() const
Definition: team.hpp:316
The unit is slowed - it moves slower and does less damage.
Definition: unit.hpp:809
const terrain_code FOGGED
#define REPORT_GENERATOR(n, cn)
Definition: reports.cpp:118
void register_generator(const std::string &name, generator *)
Definition: reports.cpp:1601
std::ostringstream wrapper.
Definition: formatter.hpp:38
static const time_of_day get_visible_time_of_day_at(reports::context &rc, const map_location &hex)
Definition: reports.cpp:93
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
Definition: tod_manager.hpp:54
bool valid() const
Definition: location.hpp:93
const std::vector< std::string > advances_to_translated() const
Gets the names of the possible types this unit can advance to on level-up.
Definition: unit.cpp:1153
color_t xp_color() const
Color for this unit&#39;s XP.
Definition: unit.cpp:1101
const t_string & name() const
Definition: attack_type.hpp:40
config generate_report(const std::string &name, context &ct, bool only_static=false)
Definition: reports.cpp:1606
Encapsulates the map of the game.
Definition: map.hpp:36
const t_string & name() const
Gets this unit&#39;s translatable display name.
Definition: unit.hpp:366
static UNUSEDNOWARN std::string _n(const char *str1, const char *str2, int n)
Definition: gettext.hpp:93
const terrain_code MINUS
Computes the statistics of a battle between an attacker and a defender unit.
Definition: attack.hpp:171
const terrain_code PLUS
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:483
std::set< t_translation::terrain_code > & encountered_terrains()
Definition: game.cpp:944
const std::string & range() const
Definition: attack_type.hpp:44
bool is_enemy(int n) const
Definition: team.hpp:243
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.
Definition: abilities.cpp:665
virtual int playing_side() const
Definition: display.hpp:206
std::string path
Definition: game_config.cpp:39
int level() const
The current level of this unit.
Definition: unit.hpp:513
const std::vector< t_string > & trait_names() const
Gets the names of the currently registered traits.
Definition: unit.hpp:1026
static config unit_hp(reports::context &rc, const unit *u)
Definition: reports.cpp:432
Structure describing the statistics of a unit involved in the battle.
Definition: attack.hpp:48
static int attack_info(reports::context &rc, const attack_type &at, config &res, const unit &u, const map_location &hex)
Definition: reports.cpp:681
const t_string & type_name() const
Gets the translatable name of this unit&#39;s type.
Definition: unit.hpp:332
std::string small_profile() const
An optional profile image to display in Help.
Definition: unit.cpp:1030
const color_t YELLOW_COLOR
static UNUSEDNOWARN std::string gettext(const char *str)
Definition: gettext.hpp:66
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:130
const std::string unicode_figure_dash
Definition: constants.cpp:41
std::function< config(reports::context &)> generator_function
Definition: reports.hpp:80
std::string flag_rgb
static std::string get_side_color_id(unsigned side)
Definition: team.cpp:952
static config unit_status(reports::context &rc, const unit *u)
Definition: reports.cpp:313
Encapsulates the map of the game.
Definition: location.hpp:42
static const unit * get_visible_unit(reports::context &rc)
Definition: reports.cpp:125
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition: display.cpp:711
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 ...
Definition: math.hpp:59
unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp, unsigned max_hp)
Calculates the number of blows resulting from swarm.
Definition: attack.hpp:38
static config unit_box_at(reports::context &rc, const map_location &mouseover_hex)
Definition: reports.cpp:1167
bool invisible(const map_location &loc, bool see_all=true) const
Definition: unit.cpp:2381
All combat-related info.
const color_t weapon_details_color
bool shrouded(const map_location &loc) const
Definition: team.cpp:644
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 escape_text(const std::string &text)
Escapes the pango markup characters in a text.
Definition: escape.hpp:32
static config unit_moves(reports::context &rc, const unit *u)
Definition: reports.cpp:608
std::size_t i
Definition: function.cpp:933
const display_context & dc() const
Definition: reports.hpp:54
const std::string unicode_en_dash
Definition: constants.cpp:39
int damage() const
Definition: attack_type.hpp:50
std::vector< std::tuple< std::string, t_string, t_string, t_string > > ability_tooltips(boost::dynamic_bitset<> *active_list=nullptr) const
Gets the names and descriptions of this unit&#39;s abilities.
Definition: abilities.cpp:268
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:459
int accuracy() const
Definition: attack_type.hpp:48
std::string resistance_color(const int resistance)
Definition: helper.cpp:35
static const unit * get_selected_unit(reports::context &rc)
Definition: reports.cpp:132
static void add_image(config &report, const std::string &image, const std::string &tooltip, const std::string &help="")
Definition: reports.cpp:51
static map_location::DIRECTION s
bool show_variations_in_help() const
Whether the unit type has at least one help-visible variation.
Definition: types.cpp:786
const std::string & flag_icon() const
Definition: team.hpp:301
const unit_map & units() const
Definition: reports.hpp:51
t_translation::terrain_code number() const
Definition: terrain.hpp:44
const t_string & income_description_own() const
Definition: terrain.hpp:74
double g
Definition: astarsearch.cpp:64
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
Definition: color.cpp:97
std::string signed_percent(int val)
Convert into a percentage (using the Unicode "−" and +0% convention.
const t_string & income_description_enemy() const
Definition: terrain.hpp:73
attack_itors attacks()
Gets an iterator over this unit&#39;s attacks.
Definition: unit.hpp:874
std::map< std::string, std::string > advancement_icons() const
Gets and image path and and associated description for each advancement option.
Definition: unit.cpp:1664
std::string accuracy_parry_description() const
Definition: attack_type.cpp:77
static std::string flush(std::ostringstream &s)
Definition: reports.cpp:86
double get_battery_percentage()
int modified_damage(bool is_backstab) const
Returns the damage per attack of this weapon, considering specials.
Definition: abilities.cpp:850
const t_translation::ter_list & union_type() const
Definition: terrain.hpp:50
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has.
Definition: unit.cpp:882
const unit_race * race() const
Gets this unit&#39;s race.
Definition: unit.hpp:447
#define N_(String)
Definition: gettext.hpp:97
const std::string unicode_bullet
Definition: constants.cpp:43
static int sort(lua_State *L)
Definition: ltablib.cpp:411
std::string observer
static config unit_defense(reports::context &rc, const unit *u, const map_location &displayed_unit_hex)
Definition: reports.cpp:533
config & add_child(config_key_type key)
Definition: config.cpp:479
const t_string & name() const
Definition: terrain.hpp:33
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
std::map< std::string, reports::generator_function > static_report_generators
Definition: reports.cpp:107
bool is_village(const map_location &loc) const
Definition: map.cpp:65
const std::string & color() const
Definition: team.hpp:256
const ter_match ALL_OFF_MAP
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
Definition: unit.hpp:1146
const std::string weapon_numbers_sep
Definition: constants.cpp:45
double t
Definition: astarsearch.cpp:64
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:477
color_t red_to_green(int val, bool for_text)
Return a color corresponding to the value val red for val=0 to green for val=100, passing by yellow...
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1256
symbol_table string_table
Definition: language.cpp:63
std::size_t viewing_team() const
The viewing team is the team currently viewing the game.
Definition: display.hpp:102
static void add_text(config &report, const std::string &text, const std::string &tooltip, const std::string &help="")
Definition: reports.cpp:42
this module manages the cache of images.
bool can_advance() const
Checks whether this unit has any options to advance to.
Definition: unit.hpp:231
std::string tod_bright
const std::string & id() const
Definition: terrain.hpp:37
std::vector< terrain_code > ter_list
Definition: translation.hpp:78
specials_context_t specials_context_for_listing(bool attacking=true) const
t_string unit_description() const
A detailed description of this unit.
Definition: unit.hpp:413
static const map_location & null_location()
Definition: location.hpp:85
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1165
unsigned int num_blows
Effective number of blows, takes swarm into account.
Definition: attack.hpp:78
std::string base_str() const
Definition: tstring.hpp:190
bool fogged(const map_location &loc) const
Definition: team.cpp:653
const t_string & income_description_ally() const
Definition: terrain.hpp:72
std::string time_icon
static config unit_weapons(reports::context &rc, const unit *attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
Definition: reports.cpp:888
int side() const
The side this unit belongs to.
Definition: unit.hpp:303
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:193
Definition: help.cpp:56
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&#39;s resistance against a given damage type.
Definition: unit.cpp:1639
std::vector< std::pair< std::string, std::string > > amla_icons() const
Gets the image and description data for modification advancements.
Definition: unit.cpp:1704
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
static std::string alignment_description(ALIGNMENT align, unit_race::GENDER gender=unit_race::MALE)
mock_char c
static config unit_abilities(const unit *u)
Definition: reports.cpp:386
std::shared_ptr< const attack_type > const_attack_ptr
Definition: ptr.hpp:37
static config unit_vision(const unit *u)
Definition: reports.cpp:587
int bonus_modified
Definition: time_of_day.hpp:85
const std::set< map_location > & villages() const
Definition: team.hpp:184
bool use_twelve_hour_clock_format()
Definition: general.cpp:1042
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1181
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
Definition: unit.cpp:2537
const std::string & icon_image() const
Definition: terrain.hpp:29
const color_t BAD_COLOR
static game_display * get_singleton()
const std::vector< t_string > & trait_descriptions() const
Gets the descriptions of the currently registered traits.
Definition: unit.hpp:1036
int combat_modifier(const unit_map &units, const gamemap &map, const map_location &loc, unit_type::ALIGNMENT alignment, bool is_fearless)
Returns the amount that a unit&#39;s damage should be multiplied by due to the current time of day...
Definition: attack.cpp:1726
const color_t inactive_ability_color