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_types = u->advances_to_translated();
253  const std::vector<config> &adv_to_mods = u->get_modification_advances();
254  const bool has_advancements = !adv_to_types.empty() || !adv_to_mods.empty();
255  if(has_advancements) {
256  tooltip << _("Advancements:") << "\n<b>\t";
257  if(!adv_to_types.empty())
258  tooltip << utils::join(adv_to_types, "\n\t");
259  if(!adv_to_mods.empty()) {
260  if(!adv_to_types.empty())
261  tooltip << "\n\t";
262  std::vector<std::string> descriptions;
263  for(const config& adv : adv_to_mods)
264  descriptions.push_back(adv["description"].str());
265  tooltip << utils::join(descriptions, "\n\t");
266  }
267  tooltip << "</b>";
268  } else {
269  tooltip << _("No advancement");
270  }
271  return text_report(str.str(), tooltip.str());
272 }
274 {
275  const unit *u = get_visible_unit(rc);
276  return unit_level(u);
277 }
278 REPORT_GENERATOR(selected_unit_level, rc)
279 {
280  const unit *u = get_selected_unit(rc);
281  return unit_level(u);
282 }
283 
284 REPORT_GENERATOR(unit_amla, rc)
285 {
286  const unit *u = get_visible_unit(rc);
287  if (!u) return config();
288  config res;
289  typedef std::pair<std::string, std::string> pair_string;
290  for (const pair_string &ps : u->amla_icons()) {
291  add_image(res, ps.first, ps.second);
292  }
293  return res;
294 }
295 
296 static config unit_traits(const unit* u)
297 {
298  if (!u) return config();
299  config res;
300  const std::vector<t_string> &traits = u->trait_names();
301  const std::vector<t_string> &descriptions = u->trait_descriptions();
302  const std::vector<std::string> &trait_ids = u->get_traits_list();
303  unsigned nb = traits.size();
304  for (unsigned i = 0; i < nb; ++i)
305  {
306  std::ostringstream str, tooltip;
307  str << traits[i];
308  if (i != nb - 1 ) str << ", ";
309  tooltip << _("Trait: ") << "<b>" << traits[i] << "</b>\n"
310  << descriptions[i];
311  add_text(res, str.str(), tooltip.str(), "traits_" + trait_ids[i]);
312  }
313  return res;
314 }
316 {
317  const unit *u = get_visible_unit(rc);
318  return unit_traits(u);
319 }
320 REPORT_GENERATOR(selected_unit_traits, rc)
321 {
322  const unit *u = get_selected_unit(rc);
323  return unit_traits(u);
324 }
325 
326 static config unit_status(reports::context & rc, const unit* u)
327 {
328  if (!u) return config();
329  config res;
330  map_location displayed_unit_hex = rc.screen().displayed_unit_hex();
331  if (rc.map().on_board(displayed_unit_hex) && u->invisible(displayed_unit_hex)) {
332  add_status(res, "misc/invisible.png", N_("invisible: "),
333  N_("This unit is invisible. It cannot be seen or attacked by enemy units."));
334  }
335  if (u->get_state(unit::STATE_SLOWED)) {
336  add_status(res, "misc/slowed.png", N_("slowed: "),
337  N_("This unit has been slowed. It will only deal half its normal damage when attacking and its movement cost is doubled."));
338  }
340  add_status(res, "misc/poisoned.png", N_("poisoned: "),
341  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."));
342  }
344  add_status(res, "misc/petrified.png", N_("petrified: "),
345  N_("This unit has been petrified. It may not move or attack."));
346  }
347  return res;
348 }
350 {
351  const unit *u = get_visible_unit(rc);
352  return unit_status(rc,u);
353 }
354 REPORT_GENERATOR(selected_unit_status, rc)
355 {
356  const unit *u = get_selected_unit(rc);
357  return unit_status(rc, u);
358 }
359 
360 static config unit_alignment(reports::context & rc, const unit* u, const map_location& hex)
361 {
362  if (!u) return config();
363  std::ostringstream str, tooltip;
364  const std::string align = unit_type::alignment_description(u->alignment(), u->gender());
365  const std::string align_id = u->alignment().to_string();
366  const time_of_day effective_tod = get_visible_time_of_day_at(rc, hex);
367  int cm = combat_modifier(effective_tod, u->alignment(), u->is_fearless());
368 
369  color_t color = font::weapon_color;
370  if (cm != 0)
371  color = (cm > 0) ? font::good_dmg_color : font::bad_dmg_color;
372 
373  str << align << " (" << span_color(color) << utils::signed_percent(cm)
374  << naps << ")";
375 
376  tooltip << _("Alignment: ") << "<b>" << align << "</b>\n"
377  << string_table[align_id + "_description"];
378 
379  return text_report(str.str(), tooltip.str(), "time_of_day");
380 }
382 {
383  const unit *u = get_visible_unit(rc);
384  const map_location& mouseover_hex = rc.screen().mouseover_hex();
385  const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
386  const map_location& hex = mouseover_hex.valid() ? mouseover_hex : displayed_unit_hex;
387  return unit_alignment(rc, u, hex);
388 }
389 REPORT_GENERATOR(selected_unit_alignment, rc)
390 {
391  const unit *u = get_selected_unit(rc);
392  const map_location& attack_indicator_src = game_display::get_singleton()->get_attack_indicator_src();
393  const map_location& hex_to_show_alignment_at =
394  attack_indicator_src.valid() ? attack_indicator_src : u->get_location();
395  return unit_alignment(rc, u, hex_to_show_alignment_at);
396 }
397 
398 static config unit_abilities(const unit* u, const map_location& loc)
399 {
400  if (!u) return config();
401  config res;
402 
403  boost::dynamic_bitset<> active;
404  const std::vector<std::tuple<std::string, t_string,t_string,t_string>> &abilities = u->ability_tooltips(active, loc);
405  const std::size_t abilities_size = abilities.size();
406  for ( std::size_t i = 0; i != abilities_size; ++i )
407  {
408  // Aliases for readability:
409  const std::string& id = std::get<0>(abilities[i]);
410  const std::string& base_name = std::get<1>(abilities[i]).base_str();
411  const t_string& display_name = std::get<2>(abilities[i]);
412  const t_string& description = std::get<3>(abilities[i]);
413 
414  std::ostringstream str, tooltip;
415 
416  if ( active[i] )
417  str << display_name;
418  else
419  str << span_color(font::inactive_ability_color) << display_name << naps;
420  if ( i + 1 != abilities_size )
421  str << ", ";
422 
423  tooltip << _("Ability: ") << "<b>" << display_name << "</b>";
424  if ( !active[i] )
425  tooltip << "<i>" << _(" (inactive)") << "</i>";
426  tooltip << '\n' << description;
427 
428  add_text(res, str.str(), tooltip.str(), "ability_" + id + base_name);
429  }
430  return res;
431 }
433 {
434  const unit *u = get_visible_unit(rc);
435  const map_location& mouseover_hex = rc.screen().mouseover_hex();
436 
437  return unit_abilities(u, mouseover_hex);
438 }
439 REPORT_GENERATOR(selected_unit_abilities, rc)
440 {
441  const unit *u = get_selected_unit(rc);
442 
443  const map_location& mouseover_hex = rc.screen().mouseover_hex();
444  const unit *visible_unit = get_visible_unit(rc);
445  if(visible_unit && u && visible_unit->id() != u->id() && mouseover_hex.valid())
446  return unit_abilities(u, mouseover_hex);
447  else
448  return unit_abilities(u, u->get_location());
449 }
450 
451 
452 static config unit_hp(reports::context& rc, const unit* u)
453 {
454  if (!u) return config();
455  std::ostringstream str, tooltip;
456  str << span_color(u->hp_color()) << u->hitpoints()
457  << '/' << u->max_hitpoints() << naps;
458 
459  std::set<std::string> resistances_table;
460 
461  bool att_def_diff = false;
462  map_location displayed_unit_hex = rc.screen().displayed_unit_hex();
463  for (const utils::string_map::value_type &resist : u->get_base_resistances())
464  {
465  std::ostringstream line;
466  line << translation::gettext(resist.first.c_str()) << ": ";
467  // Some units have different resistances when attacking or defending.
468  int res_att = 100 - u->resistance_against(resist.first, true, displayed_unit_hex);
469  int res_def = 100 - u->resistance_against(resist.first, false, displayed_unit_hex);
470  const std::string def_color = unit_helper::resistance_color(res_def);
471  if (res_att == res_def) {
472  line << "<span foreground=\"" << def_color << "\">" << utils::signed_percent(res_def)
473  << naps << '\n';
474  } else {
475  const std::string att_color = unit_helper::resistance_color(res_att);
476  line << "<span foreground=\"" << att_color << "\">" << utils::signed_percent(res_att)
477  << naps << "/"
478  << "<span foreground=\"" << def_color << "\">" << utils::signed_percent(res_def)
479  << naps << '\n';
480  att_def_diff = true;
481  }
482  resistances_table.insert(line.str());
483  }
484 
485  tooltip << _("Resistances: ");
486  if (att_def_diff)
487  tooltip << _("(Att / Def)");
488  tooltip << '\n';
489  for (const std::string &line : resistances_table) {
490  tooltip << line;
491  }
492  return text_report(str.str(), tooltip.str());
493 }
495 {
496  const unit *u = get_visible_unit(rc);
497  return unit_hp(rc, u);
498 }
499 REPORT_GENERATOR(selected_unit_hp, rc)
500 {
501  const unit *u = get_selected_unit(rc);
502  return unit_hp(rc, u);
503 }
504 
505 static config unit_xp(const unit* u)
506 {
507  if (!u) return config();
508  std::ostringstream str, tooltip;
509  str << span_color(u->xp_color());
510  if(u->can_advance()) {
511  str << u->experience() << '/' << u->max_experience();
512  } else {
513  str << font::unicode_en_dash;
514  }
515  str << naps;
516 
518  tooltip << _("Experience Modifier: ") << exp_mod << '%';
519  return text_report(str.str(), tooltip.str());
520 }
522 {
523  const unit *u = get_visible_unit(rc);
524  return unit_xp(u);
525 }
526 REPORT_GENERATOR(selected_unit_xp, rc)
527 {
528  const unit *u = get_selected_unit(rc);
529  return unit_xp(u);
530 }
531 
533 {
534  if (!u) return config();
535  config res;
536  typedef std::pair<std::string, std::string> pair_string;
537  for (const pair_string &ps : u->advancement_icons()) {
538  add_image(res, ps.first, ps.second);
539  }
540  return res;
541 }
543 {
544  const unit *u = get_visible_unit(rc);
545  return unit_advancement_options(u);
546 }
547 REPORT_GENERATOR(selected_unit_advancement_options, rc)
548 {
549  const unit *u = get_selected_unit(rc);
550  return unit_advancement_options(u);
551 }
552 
553 static config unit_defense(reports::context & rc, const unit* u, const map_location& displayed_unit_hex)
554 {
555  if(!u) {
556  return config();
557  }
558 
559  std::ostringstream str, tooltip;
560  const gamemap &map = rc.map();
561  if(!rc.map().on_board(displayed_unit_hex)) {
562  return config();
563  }
564 
565  const t_translation::terrain_code &terrain = map[displayed_unit_hex];
566  int def = 100 - u->defense_modifier(terrain);
567  color_t color = game_config::red_to_green(def);
568  str << span_color(color) << def << '%' << naps;
569  tooltip << _("Terrain: ") << "<b>" << map.get_terrain_info(terrain).description() << "</b>\n";
570 
571  const t_translation::ter_list &underlyings = map.underlying_def_terrain(terrain);
572  if (underlyings.size() != 1 || underlyings.front() != terrain)
573  {
574  bool revert = false;
575  for (const t_translation::terrain_code &t : underlyings)
576  {
577  if (t == t_translation::MINUS) {
578  revert = true;
579  } else if (t == t_translation::PLUS) {
580  revert = false;
581  } else {
582  int t_def = 100 - u->defense_modifier(t);
583  color_t t_color = game_config::red_to_green(t_def);
584  tooltip << '\t' << map.get_terrain_info(t).description() << ": "
585  << span_color(t_color) << t_def << '%' << naps
586  << (revert ? _("maximum^max.") : _("minimum^min.")) << '\n';
587  }
588  }
589  }
590 
591  tooltip << "<b>" << _("Defense: ") << span_color(color) << def << '%' << naps << "</b>";
592  return text_report(str.str(), tooltip.str());
593 }
595 {
596  const unit *u = get_visible_unit(rc);
597  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
598  const map_location& mouseover_hex = rc.screen().mouseover_hex();
599  const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
600  const map_location& hex = (mouseover_hex.valid() && !viewing_team.shrouded(mouseover_hex)) ? mouseover_hex : displayed_unit_hex;
601  return unit_defense(rc, u, hex);
602 }
603 REPORT_GENERATOR(selected_unit_defense, rc)
604 {
605  const unit *u = get_selected_unit(rc);
606  const map_location& attack_indicator_src = game_display::get_singleton()->get_attack_indicator_src();
607  if(attack_indicator_src.valid())
608  return unit_defense(rc, u, attack_indicator_src);
609 
610  const map_location& mouseover_hex = rc.screen().mouseover_hex();
611  const unit *visible_unit = get_visible_unit(rc);
612  if(visible_unit && u && visible_unit->id() != u->id() && mouseover_hex.valid())
613  return unit_defense(rc, u, mouseover_hex);
614  else
615  return unit_defense(rc, u, u->get_location());
616 }
617 
618 static config unit_vision(const unit* u)
619 {
620  if (!u) return config();
621 
622  // TODO
623  std::ostringstream str;
624  if (u->vision() != u->total_movement()) {
625  str << _("vision: ") << u->vision(); }
626  return text_report(str.str(), str.str());
627 }
629 {
630  const unit* u = get_visible_unit(rc);
631  return unit_vision(u);
632 }
633 REPORT_GENERATOR(selected_unit_vision, rc)
634 {
635  const unit* u = get_selected_unit(rc);
636  return unit_vision(u);
637 }
638 
639 static config unit_moves(reports::context & rc, const unit* u)
640 {
641  if (!u) return config();
642  std::ostringstream str, tooltip;
643  double movement_frac = 1.0;
644 
645  std::set<terrain_movement> terrain_moves;
646 
647  if (u->side() == rc.screen().playing_side()) {
648  movement_frac = static_cast<double>(u->movement_left()) / std::max<int>(1, u->total_movement());
649  if (movement_frac > 1.0)
650  movement_frac = 1.0;
651  }
652 
653  tooltip << _("Movement Costs:") << "\n";
656  continue;
657 
659 
660  if (info.union_type().size() == 1 && info.union_type()[0] == info.number() && info.is_nonnull()) {
661  terrain_moves.emplace(info.name(), u->movement_cost(terrain));
662  }
663  }
664 
665  for (const terrain_movement& tm : terrain_moves) {
666  tooltip << tm.name << ": ";
667 
668  std::string color;
669  //movement - range: 1 .. 5, movetype::UNREACHABLE=impassable
670  const bool cannot_move = tm.moves > u->total_movement();
671  if (cannot_move) // cannot move in this terrain
672  color = "red";
673  else if (tm.moves > 1)
674  color = "yellow";
675  else
676  color = "white";
677  tooltip << "<span foreground=\"" << color << "\">";
678  // A 5 MP margin; if the movement costs go above
679  // the unit's max moves + 5, we replace it with dashes.
680  if (cannot_move && (tm.moves > u->total_movement() + 5)) {
681  tooltip << font::unicode_figure_dash;
682  } else {
683  tooltip << tm.moves;
684  }
685  tooltip << naps << '\n';
686  }
687 
688  int grey = 128 + static_cast<int>((255 - 128) * movement_frac);
689  color_t c = color_t(grey, grey, grey);
690  str << span_color(c) << u->movement_left() << '/' << u->total_movement() << naps;
691  return text_report(str.str(), tooltip.str());
692 }
694 {
695  const unit *u = get_visible_unit(rc);
696  return unit_moves(rc, u);
697 }
698 REPORT_GENERATOR(selected_unit_moves, rc)
699 {
700  const unit *u = get_selected_unit(rc);
701  return unit_moves(rc, u);
702 }
703 
704 static inline const color_t attack_info_percent_color(int resistance)
705 {
706  // Compare unit_helper::resistance_color()
707  if (resistance < 0) return font::BAD_COLOR;
708  if (resistance > 0) return font::GOOD_COLOR;
709  return font::YELLOW_COLOR;
710 }
711 
712 static int attack_info(reports::context & rc, const attack_type &at, config &res, const unit &u, const map_location &hex)
713 {
714  std::ostringstream str, tooltip;
715  int damage = 0;
716 
717  {
718  auto ctx = at.specials_context(unit_const_ptr(&u), hex, u.side() == rc.screen().playing_side());
719  int base_damage = at.damage();
720  int specials_damage = at.modified_damage(false);
721  int damage_multiplier = 100;
722  const_attack_ptr weapon = at.shared_from_this();
723  int tod_bonus = combat_modifier(get_visible_time_of_day_at(rc, hex), u.alignment(), u.is_fearless());
724  damage_multiplier += tod_bonus;
725  int leader_bonus = under_leadership(u, hex, weapon);
726  if (leader_bonus != 0)
727  damage_multiplier += leader_bonus;
728 
730  int damage_divisor = slowed ? 20000 : 10000;
731  // Assume no specific resistance (i.e. multiply by 100).
732  damage = round_damage(specials_damage, damage_multiplier * 100, damage_divisor);
733 
734  // Hit points are used to calculate swarm, so they need to be bounded.
735  unsigned max_hp = u.max_hitpoints();
736  unsigned cur_hp = std::min<unsigned>(std::max(0, u.hitpoints()), max_hp);
737 
738  unsigned base_attacks = at.num_attacks();
739  unsigned min_attacks, max_attacks;
740  at.modified_attacks(false, min_attacks, max_attacks);
741  unsigned num_attacks = swarm_blows(min_attacks, max_attacks, cur_hp, max_hp);
742 
743  color_t dmg_color = font::weapon_color;
744  if ( damage > specials_damage )
745  dmg_color = font::good_dmg_color;
746  else if ( damage < specials_damage )
747  dmg_color = font::bad_dmg_color;
748 
749  str << span_color(dmg_color) << " " << damage << naps << span_color(font::weapon_color)
750  << font::weapon_numbers_sep << num_attacks << ' ' << at.name()
751  << "</span>\n";
752  tooltip << _("Weapon: ") << "<b>" << at.name() << "</b>\n"
753  << _("Damage: ") << "<b>" << damage << "</b>\n";
754 
755  if ( tod_bonus || leader_bonus || slowed || specials_damage != base_damage )
756  {
757  tooltip << '\t' << _("Base damage: ") << base_damage << '\n';
758  if ( specials_damage != base_damage ) {
759  tooltip << '\t' << _("With specials: ") << specials_damage << '\n';
760  }
761  if (tod_bonus) {
762  tooltip << '\t' << _("Time of day: ")
763  << utils::signed_percent(tod_bonus) << '\n';
764  }
765  if (leader_bonus) {
766  tooltip << '\t' << _("Leadership: ")
767  << utils::signed_percent(leader_bonus) << '\n';
768  }
769  if (slowed) {
770  tooltip << '\t' << _("Slowed: ") << "/ 2" << '\n';
771  }
772  }
773 
774  tooltip << _("Attacks: ") << "<b>" << num_attacks << "</b>\n";
775  if ( max_attacks != min_attacks && cur_hp != max_hp ) {
776  if ( max_attacks < min_attacks ) {
777  // "Reverse swarm"
778  tooltip << '\t' << _("Max swarm bonus: ") << (min_attacks-max_attacks) << '\n';
779  tooltip << '\t' << _("Swarm: ") << "* "<< (100 - cur_hp*100/max_hp) << "%\n";
780  tooltip << '\t' << _("Base attacks: ") << '+' << base_attacks << '\n';
781  // The specials line will not necessarily match up with how the
782  // specials are calculated, but for an unusual case, simple brevity
783  // trumps complexities.
784  if ( max_attacks != base_attacks ) {
785  int attack_diff = static_cast<int>(max_attacks) - static_cast<int>(base_attacks);
786  tooltip << '\t' << _("Specials: ") << utils::signed_value(attack_diff) << '\n';
787  }
788  }
789  else {
790  // Regular swarm
791  tooltip << '\t' << _("Base attacks: ") << base_attacks << '\n';
792  if ( max_attacks != base_attacks ) {
793  tooltip << '\t' << _("With specials: ") << max_attacks << '\n';
794  }
795  if ( min_attacks != 0 ) {
796  tooltip << '\t' << _("Subject to swarm: ") << (max_attacks-min_attacks) << '\n';
797  }
798  tooltip << '\t' << _("Swarm: ") << "* "<< (cur_hp*100/max_hp) << "%\n";
799  }
800  }
801  else if ( num_attacks != base_attacks ) {
802  tooltip << '\t' << _("Base attacks: ") << base_attacks << '\n';
803  tooltip << '\t' << _("With specials: ") << num_attacks << '\n';
804  }
805 
806  add_text(res, flush(str), flush(tooltip));
807 
808  std::string range = string_table["range_" + at.range()];
809  std::string lang_type = string_table["type_" + at.type()];
810 
811  str << span_color(font::weapon_details_color) << " " << " "
812  << range << font::weapon_details_sep
813  << lang_type << "</span>\n";
814 
815  tooltip << _("Weapon range: ") << "<b>" << range << "</b>\n"
816  << _("Damage type: ") << "<b>" << lang_type << "</b>\n"
817  << _("Damage versus: ") << '\n';
818 
819  // Show this weapon damage and resistance against all the different units.
820  // We want weak resistances (= good damage) first.
821  std::map<int, std::set<std::string>, std::greater<int>> resistances;
822  std::set<std::string> seen_types;
823  const team &unit_team = rc.dc().get_team(u.side());
824  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
825  for (const unit &enemy : rc.units())
826  {
827  if (enemy.incapacitated()) //we can't attack statues so don't display them in this tooltip
828  continue;
829  if (!unit_team.is_enemy(enemy.side()))
830  continue;
831  const map_location &loc = enemy.get_location();
832  if (viewing_team.fogged(loc) ||
833  (viewing_team.is_enemy(enemy.side()) && enemy.invisible(loc)))
834  continue;
835  bool new_type = seen_types.insert(enemy.type_id()).second;
836  if (new_type) {
837  int resistance = enemy.resistance_against(at, false, loc);
838  resistances[resistance].insert(enemy.type_name());
839  }
840  }
841 
842  typedef std::pair<int, std::set<std::string>> resist_units;
843  for (const resist_units &resist : resistances) {
844  int damage_with_resistance = round_damage(specials_damage, damage_multiplier * resist.first, damage_divisor);
845  tooltip << "<b>" << damage_with_resistance << "</b> "
846  << "<span color='" << attack_info_percent_color(resist.first-100).to_hex_string() << "'>"
847  << "<i>(" << utils::signed_percent(resist.first-100) << ")</i>"
848  << naps
849  << " : \t" // spaces to align the tab to a multiple of 8
850  << utils::join(resist.second, " " + font::unicode_bullet + " ") << '\n';
851  }
852  add_text(res, flush(str), flush(tooltip));
853 
854  const std::string &accuracy_parry = at.accuracy_parry_description();
855  if (!accuracy_parry.empty())
856  {
858  << " " << accuracy_parry << "</span>\n";
859  int accuracy = at.accuracy();
860  if (accuracy) {
861  tooltip << _("Accuracy:") << "<b>"
862  << utils::signed_percent(accuracy) << "</b>\n";
863  }
864  int parry = at.parry();
865  if (parry) {
866  tooltip << _("Parry:") << "<b>"
867  << utils::signed_percent(parry) << "</b>\n";
868  }
869  add_text(res, flush(str), flush(tooltip));
870  }
871  }
872 
873  {
874  auto ctx = at.specials_context_for_listing(u.side() == rc.screen().playing_side());
875  boost::dynamic_bitset<> active;
876  const std::vector<std::pair<t_string, t_string>> &specials = at.special_tooltips(&active);
877  const std::size_t specials_size = specials.size();
878  for ( std::size_t i = 0; i != specials_size; ++i )
879  {
880  // Aliases for readability:
881  const t_string &name = specials[i].first;
882  const t_string &description = specials[i].second;
883  const color_t &details_color = active[i] ? font::weapon_details_color :
885 
886  str << span_color(details_color) << " " << " " << name << naps << '\n';
887  std::string help_page = "weaponspecial_" + name.base_str();
888  tooltip << _("Weapon special: ") << "<b>" << name << "</b>";
889  if ( !active[i] )
890  tooltip << "<i>" << _(" (inactive)") << "</i>";
891  tooltip << '\n' << description;
892 
893  add_text(res, flush(str), flush(tooltip), help_page);
894  }
895  }
896  return damage;
897 }
898 
899 // Conversion routine for both unscathed and damage change percentage.
900 static std::string format_prob(double prob)
901 {
902  if(prob > 0.9995) {
903  return "100%";
904  } else if(prob < 0.0005) {
905  return "0%";
906  }
907  std::ostringstream res;
908  res << std::setprecision(prob < 0.1 ? 2 : 3) << 100.0 * prob << "%";
909  return res.str();
910 }
911 
912 static std::string format_hp(unsigned hp)
913 {
914  std::ostringstream res;
915  res << ' ' << std::setw(3) << hp;
916  return res.str();
917 }
918 
919 static config unit_weapons(reports::context & rc, const unit *attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
920 {
921  if (!attacker || !defender) return config();
922 
923  const unit* u = show_attacker ? attacker : defender;
924  const map_location unit_loc = show_attacker ? attacker_pos : defender->get_location();
925 
926  std::ostringstream str, tooltip;
927  config res;
928 
929  std::vector<battle_context> weapons;
930  for (unsigned int i = 0; i < attacker->attacks().size(); i++) {
931  // skip weapons with attack_weight=0
932  if (attacker->attacks()[i].attack_weight() > 0) {
933  weapons.emplace_back(rc.units(), attacker_pos, defender->get_location(), i, -1, 0.0, nullptr, attacker);
934  }
935  }
936 
937  for (const battle_context& weapon : weapons) {
938 
939  // Predict the battle outcome.
940  combatant attacker_combatant(weapon.get_attacker_stats());
941  combatant defender_combatant(weapon.get_defender_stats());
942  attacker_combatant.fight(defender_combatant);
943 
944  const battle_context_unit_stats& context_unit_stats =
945  show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
946 
947  int total_damage = 0;
948  int base_damage = 0;
949  int num_blows = 0;
950  int chance_to_hit = 0;
951  t_string weapon_name = _("weapon^None");
952 
953  color_t dmg_color = font::weapon_color;
954  if (context_unit_stats.weapon) {
955  base_damage = attack_info(rc, *context_unit_stats.weapon, res, *u, unit_loc);
956  total_damage = context_unit_stats.damage;
957  num_blows = context_unit_stats.num_blows;
958  chance_to_hit = context_unit_stats.chance_to_hit;
959  weapon_name = context_unit_stats.weapon->name();
960 
961  if ( total_damage > base_damage )
962  dmg_color = font::good_dmg_color;
963  else if ( total_damage < base_damage )
964  dmg_color = font::bad_dmg_color;
965  } else {
966  str << span_color(font::weapon_color) << weapon_name << naps << "\n";
967  tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
968  << _("Damage: ") << "<b>" << "0" << "</b>\n";
969  }
970 
971  color_t chance_color = game_config::red_to_green(chance_to_hit);
972 
973  // Total damage.
974  str << " " << span_color(dmg_color) << total_damage << naps << span_color(font::weapon_color)
975  << font::unicode_en_dash << num_blows
976  << " (" << span_color(chance_color) << chance_to_hit << "%" << naps << ")"
977  << naps << "\n";
978 
979  tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
980  << _("Total damage") << "<b>" << total_damage << "</b>\n";
981 
982  // Create the hitpoints distribution.
983  std::vector<std::pair<int, double>> hp_prob_vector;
984 
985  // First, we sort the probabilities in ascending order.
986  std::vector<std::pair<double, int>> prob_hp_vector;
987  int i;
988 
989  combatant* c = show_attacker ? &attacker_combatant : &defender_combatant;
990 
991  for(i = 0; i < static_cast<int>(c->hp_dist.size()); i++) {
992  double prob = c->hp_dist[i];
993 
994  // We keep only values above 0.1%.
995  if(prob > 0.001)
996  prob_hp_vector.emplace_back(prob, i);
997  }
998 
999  std::sort(prob_hp_vector.begin(), prob_hp_vector.end());
1000 
1001  //TODO fendrin -- make that dynamically
1002  int max_hp_distrib_rows_ = 10;
1003 
1004  // We store a few of the highest probability hitpoint values.
1005  int nb_elem = std::min<int>(max_hp_distrib_rows_, prob_hp_vector.size());
1006 
1007  for(i = prob_hp_vector.size() - nb_elem;
1008  i < static_cast<int>(prob_hp_vector.size()); i++) {
1009 
1010  hp_prob_vector.emplace_back(prob_hp_vector[i].second, prob_hp_vector[i].first);
1011  }
1012 
1013  // Then, we sort the hitpoint values in ascending order.
1014  std::sort(hp_prob_vector.begin(), hp_prob_vector.end());
1015  // And reverse the order. Might be doable in a better manor.
1016  std::reverse(hp_prob_vector.begin(), hp_prob_vector.end());
1017 
1018  for(i = 0; i < static_cast<int>(hp_prob_vector.size()); i++) {
1019 
1020  int hp = hp_prob_vector[i].first;
1021  double prob = hp_prob_vector[i].second;
1022  color_t prob_color = game_config::blue_to_white(prob * 100.0, true);
1023 
1024  str << span_color(font::weapon_details_color) << " " << " "
1025  << span_color(u->hp_color(hp)) << format_hp(hp) << naps
1026  << " " << font::weapon_numbers_sep << " "
1027  << span_color(prob_color) << format_prob(prob) << naps
1028  << naps << "\n";
1029  }
1030 
1031  add_text(res, flush(str), flush(tooltip));
1032  }
1033  return res;
1034 }
1035 
1036 /*
1037  * Display the attacks of the displayed unit against the unit passed as argument.
1038  * 'hex' is the location the attacker will be at during combat.
1039  */
1040 static config unit_weapons(reports::context & rc, const unit *u, const map_location &hex)
1041 {
1042  config res = config();
1043  if ((u != nullptr) && (!u->attacks().empty())) {
1044  const std::string attack_headline = _n("Attack", "Attacks", u->attacks().size());
1045 
1047  + attack_headline + "</span>" + '\n', "");
1048 
1049  for (const attack_type &at : u->attacks())
1050  {
1051  attack_info(rc, at, res, *u, hex);
1052  }
1053  }
1054  return res;
1055 }
1057 {
1058  const unit *u = get_visible_unit(rc);
1059  const map_location& mouseover_hex = rc.screen().mouseover_hex();
1060  const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
1061  const map_location& hex = mouseover_hex.valid() ? mouseover_hex : displayed_unit_hex;
1062  if (!u) return config();
1063 
1064  return unit_weapons(rc, u, hex);
1065 }
1066 REPORT_GENERATOR(highlighted_unit_weapons, rc)
1067 {
1068  const unit *u = get_selected_unit(rc);
1069  const unit *sec_u = get_visible_unit(rc);
1070 
1071  if (!u) return report_unit_weapons(rc);
1072  if (!sec_u || u == sec_u) return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1073 
1074  map_location highlighted_hex = rc.screen().displayed_unit_hex();
1075  map_location attack_loc;
1076  if (rc.mhb())
1077  attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1078 
1079  if (!attack_loc.valid())
1080  return unit_weapons(rc, sec_u, rc.screen().mouseover_hex());
1081 
1082  return unit_weapons(rc, u, attack_loc, sec_u, false);
1083 }
1084 REPORT_GENERATOR(selected_unit_weapons, rc)
1085 {
1086  const unit *u = get_selected_unit(rc);
1087  const unit *sec_u = get_visible_unit(rc);
1088 
1089  if (!u) return config();
1090  if (!sec_u || u == sec_u) return unit_weapons(rc, u, u->get_location());
1091 
1092  map_location highlighted_hex = rc.screen().displayed_unit_hex();
1093  map_location attack_loc;
1094  if (rc.mhb())
1095  attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1096 
1097  if (!attack_loc.valid())
1098  return unit_weapons(rc, u, u->get_location());
1099 
1100  return unit_weapons(rc, u, attack_loc, sec_u, true);
1101 }
1102 
1103 REPORT_GENERATOR(unit_image,rc)
1104 {
1105  const unit *u = get_visible_unit(rc);
1106  if (!u) return config();
1107  return image_report(u->absolute_image() + u->image_mods());
1108 }
1109 REPORT_GENERATOR(selected_unit_image, rc)
1110 {
1111  const unit *u = get_selected_unit(rc);
1112  if (!u) return config();
1113  return image_report(u->absolute_image() + u->image_mods());
1114 }
1115 
1116 REPORT_GENERATOR(selected_unit_profile, rc)
1117 {
1118  const unit *u = get_selected_unit(rc);
1119  if (!u) return config();
1120  return image_report(u->small_profile());
1121 }
1122 REPORT_GENERATOR(unit_profile, rc)
1123 {
1124  const unit *u = get_visible_unit(rc);
1125  if (!u) return config();
1126  return image_report(u->small_profile());
1127 }
1128 
1130 {
1131  std::ostringstream tooltip;
1132  std::ostringstream text;
1133 
1134  const map_location& tod_schedule_hex = (hex.valid() && !display::get_singleton()->shrouded(hex)) ? hex : map_location::null_location();
1135  const std::vector<time_of_day>& schedule = rc.tod().times(tod_schedule_hex);
1136 
1137  int current = rc.tod().get_current_time(tod_schedule_hex);
1138  int i = 0;
1139  for (const time_of_day& tod : schedule) {
1140  if (i == current) tooltip << "<big><b>";
1141  tooltip << tod.name << "\n";
1142  if (i == current) tooltip << "</b></big>";
1143  i++;
1144  }
1145 
1146  int times = schedule.size();
1147  text << current + 1 << "/" << times;
1148 
1149  return text_report(text.str(), tooltip.str(), "..schedule");
1150 }
1151 REPORT_GENERATOR(tod_stats, rc)
1152 {
1153  map_location mouseover_hex = rc.screen().mouseover_hex();
1154  if (mouseover_hex.valid()) return tod_stats_at(rc, mouseover_hex);
1155  return tod_stats_at(rc, rc.screen().selected_hex());
1156 }
1157 REPORT_GENERATOR(selected_tod_stats, rc)
1158 {
1159  const unit *u = get_selected_unit(rc);
1160  if(!u) return tod_stats_at(rc, map_location::null_location());
1161  const map_location& attack_indicator_src = game_display::get_singleton()->get_attack_indicator_src();
1162  const map_location& hex =
1163  attack_indicator_src.valid() ? attack_indicator_src : u->get_location();
1164  return tod_stats_at(rc, hex);
1165 }
1166 
1167 static config time_of_day_at(reports::context & rc, const map_location& mouseover_hex)
1168 {
1169  std::ostringstream tooltip;
1170  time_of_day tod = get_visible_time_of_day_at(rc, mouseover_hex);
1171 
1172  int b = tod.lawful_bonus;
1173  int l = generic_combat_modifier(b, unit_type::ALIGNMENT::LIMINAL, false, rc.tod().get_max_liminal_bonus());
1174  std::string lawful_color("white");
1175  std::string chaotic_color("white");
1176  std::string liminal_color("white");
1177 
1178  if (b != 0) {
1179  lawful_color = (b > 0) ? "green" : "red";
1180  chaotic_color = (b < 0) ? "green" : "red";
1181  }
1182  if (l != 0) {
1183  liminal_color = (l > 0) ? "green" : "red";
1184  }
1185  tooltip << tod.name << '\n'
1186  << _("Lawful units: ") << "<span foreground=\"" << lawful_color << "\">"
1187  << utils::signed_percent(b) << "</span>\n"
1188  << _("Neutral units: ") << utils::signed_percent(0) << '\n'
1189  << _("Chaotic units: ") << "<span foreground=\"" << chaotic_color << "\">"
1190  << utils::signed_percent(-b) << "</span>\n"
1191  << _("Liminal units: ") << "<span foreground=\"" << liminal_color << "\">"
1192  << utils::signed_percent(l) << "</span>\n";
1193 
1194  std::string tod_image = tod.image;
1195  if(tod.bonus_modified > 0) {
1196  tod_image += (formatter() << "~BLIT(" << game_config::images::tod_bright << ")").str();
1197  } else if(tod.bonus_modified < 0) {
1198  tod_image += (formatter() << "~BLIT(" << game_config::images::tod_dark << ")").str();
1199  }
1200 
1201  return image_report(tod_image, tooltip.str(), "time_of_day_" + tod.id);
1202 }
1204 {
1205  map_location mouseover_hex = rc.screen().mouseover_hex();
1206  if (mouseover_hex.valid()) return time_of_day_at(rc, mouseover_hex);
1207  return time_of_day_at(rc, rc.screen().selected_hex());
1208 }
1209 REPORT_GENERATOR(selected_time_of_day, rc)
1210 {
1211  const unit *u = get_selected_unit(rc);
1212  if(!u) return time_of_day_at(rc, map_location::null_location());
1213  const map_location& attack_indicator_src = game_display::get_singleton()->get_attack_indicator_src();
1214  const map_location& hex =
1215  attack_indicator_src.valid() ? attack_indicator_src : u->get_location();
1216  return time_of_day_at(rc, hex);
1217 }
1218 
1219 static config unit_box_at(reports::context & rc, const map_location& mouseover_hex)
1220 {
1221  std::ostringstream tooltip;
1222  time_of_day global_tod = rc.tod().get_time_of_day();
1223  time_of_day local_tod = get_visible_time_of_day_at(rc, mouseover_hex);
1224 
1225  int bonus = local_tod.lawful_bonus;
1226  int l = generic_combat_modifier(bonus, unit_type::ALIGNMENT::LIMINAL, false, rc.tod().get_max_liminal_bonus());
1227 
1228  std::string lawful_color("white");
1229  std::string chaotic_color("white");
1230  std::string liminal_color("white");
1231 
1232  if (bonus != 0) {
1233  lawful_color = (bonus > 0) ? "green" : "red";
1234  chaotic_color = (bonus < 0) ? "green" : "red";
1235  }
1236  if (l != 0) {
1237  liminal_color = (l > 0) ? "green" : "red";
1238  }
1239  tooltip << local_tod.name << '\n'
1240  << _("Lawful units: ") << "<span foreground=\"" << lawful_color << "\">"
1241  << utils::signed_percent(bonus) << "</span>\n"
1242  << _("Neutral units: ") << utils::signed_percent(0) << '\n'
1243  << _("Chaotic units: ") << "<span foreground=\"" << chaotic_color << "\">"
1244  << utils::signed_percent(-bonus) << "</span>\n"
1245  << _("Liminal units: ") << "<span foreground=\"" << liminal_color << "\">"
1246  << utils::signed_percent(l) << "</span>\n";
1247 
1248  std::string local_tod_image = "themes/classic/" + local_tod.image;
1249  std::string global_tod_image = "themes/classic/" + global_tod.image;
1250  if(local_tod.bonus_modified != 0) {
1251  local_tod_image += "~BLIT(";
1252  if (local_tod.bonus_modified > 0) local_tod_image += game_config::images::tod_bright;
1253  else if (local_tod.bonus_modified < 0) local_tod_image += game_config::images::tod_dark;
1254  local_tod_image += ")";
1255  }
1256 
1257  const gamemap &map = rc.map();
1258  t_translation::terrain_code terrain = map.get_terrain(mouseover_hex);
1259 
1260  //if (t_translation::terrain_matches(terrain, t_translation::ALL_OFF_MAP))
1261  // return config();
1262 
1263  //if (map.is_keep(mouseover_hex)) {
1264  // add_image(cfg, "icons/terrain/terrain_type_keep.png", "");
1265  //}
1266 
1267  const t_translation::ter_list& underlying_terrains = map.underlying_union_terrain(terrain);
1268 
1269  std::string bg_terrain_image;
1270 
1271  for (const t_translation::terrain_code& underlying_terrain : underlying_terrains) {
1272  const std::string& terrain_id = map.get_terrain_info(underlying_terrain).id();
1273  bg_terrain_image = "~BLIT(unit_env/terrain/terrain-" + terrain_id + ".png)" + bg_terrain_image;
1274  }
1275 
1276  std::stringstream color;
1277  color << local_tod.color;
1278 
1279  bg_terrain_image = bg_terrain_image + "~CS(" + color.str() + ")";
1280 
1281  const unit *u = get_visible_unit(rc);
1282  std::string unit_image;
1283  if (u)
1284  unit_image = "~BLIT(" + u->absolute_image() + u->image_mods() + ",35,22)";
1285 
1286  std::string tod_image = global_tod_image + "~BLIT(" + local_tod_image + ")";
1287 
1288  return image_report(tod_image + bg_terrain_image + unit_image, tooltip.str(), "time_of_day");
1289 }
1290 REPORT_GENERATOR(unit_box, rc)
1291 {
1292  map_location mouseover_hex = rc.screen().mouseover_hex();
1293  return unit_box_at(rc, mouseover_hex);
1294 }
1295 
1296 
1298 {
1299  std::ostringstream str, tooltip;
1300  str << rc.tod().turn();
1301  int nb = rc.tod().number_of_turns();
1302  if (nb != -1) str << '/' << nb;
1303 
1304  tooltip << _("Turn Number");
1305  if(nb != -1) {
1306  tooltip << "\n\n" << _("When the game reaches the number of turns indicated by the second number, it will end.");
1307  }
1308  return text_report(str.str(), tooltip.str());
1309 }
1310 
1312 {
1313  std::ostringstream str;
1314  int viewing_side = rc.screen().viewing_side();
1315  // Suppose the full unit map is applied.
1316  int fake_gold = rc.dc().get_team(viewing_side).gold();
1317 
1318  if (rc.wb())
1319  fake_gold -= rc.wb()->get_spent_gold_for(viewing_side);
1320  char const *end = naps;
1321  if (viewing_side != rc.screen().playing_side()) {
1322  str << span_color(font::GRAY_COLOR);
1323  }
1324  else if (fake_gold < 0) {
1325  str << span_color(font::BAD_COLOR);
1326  }
1327  else {
1328  end = "";
1329  }
1330  str << utils::half_signed_value(fake_gold) << end;
1331  return text_report(str.str(), _("Gold") + "\n\n" + _("The amount of gold currently available to recruit and maintain your army."));
1332 }
1333 
1334 REPORT_GENERATOR(villages, rc)
1335 {
1336  std::ostringstream str;
1337  int viewing_side = rc.screen().viewing_side();
1338  const team &viewing_team = rc.dc().get_team(viewing_side);
1339  str << viewing_team.villages().size() << '/';
1340  if (viewing_team.uses_shroud()) {
1341  int unshrouded_villages = 0;
1342  for (const map_location &loc : rc.map().villages()) {
1343  if (!viewing_team.shrouded(loc))
1344  ++unshrouded_villages;
1345  }
1346  str << unshrouded_villages;
1347  } else {
1348  str << rc.map().villages().size();
1349  }
1350  return gray_inactive(rc,str.str(), _("Villages") + "\n\n" + _("The fraction of known villages that your side has captured."));
1351 }
1352 
1353 REPORT_GENERATOR(num_units, rc)
1354 {
1355  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."));
1356 }
1357 
1358 REPORT_GENERATOR(upkeep, rc)
1359 {
1360  std::ostringstream str;
1361  int viewing_side = rc.screen().viewing_side();
1362  const team &viewing_team = rc.dc().get_team(viewing_side);
1363  team_data td = rc.dc().calculate_team_data(viewing_team);
1364  str << td.expenses << " (" << td.upkeep << ")";
1365  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."));
1366 }
1367 
1368 REPORT_GENERATOR(expenses, rc)
1369 {
1370  int viewing_side = rc.screen().viewing_side();
1371  const team &viewing_team = rc.dc().get_team(viewing_side);
1372  team_data td = rc.dc().calculate_team_data(viewing_team);
1373  return gray_inactive(rc,std::to_string(td.expenses));
1374 }
1375 
1376 REPORT_GENERATOR(income, rc)
1377 {
1378  std::ostringstream str;
1379  int viewing_side = rc.screen().viewing_side();
1380  const team &viewing_team = rc.dc().get_team(viewing_side);
1381  team_data td = rc.dc().calculate_team_data(viewing_team);
1382  char const *end = naps;
1383  if (viewing_side != rc.screen().playing_side()) {
1384  if (td.net_income < 0) {
1385  td.net_income = - td.net_income;
1386  str << span_color(font::GRAY_COLOR);
1387  str << font::unicode_minus;
1388  }
1389  else {
1390  str << span_color(font::GRAY_COLOR);
1391  }
1392  }
1393  else if (td.net_income < 0) {
1394  td.net_income = - td.net_income;
1395  str << span_color(font::BAD_COLOR);
1396  str << font::unicode_minus;
1397  }
1398  else {
1399  end = "";
1400  }
1401  str << td.net_income << end;
1402  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."));
1403 }
1404 
1405 namespace {
1406 void blit_tced_icon(config &cfg, const std::string &terrain_id, const std::string &icon_image, bool high_res,
1407  const std::string &terrain_name) {
1408  const std::string tc_base = high_res ? "images/buttons/icon-base-32.png" : "images/buttons/icon-base-16.png";
1409  const std::string terrain_image = "terrain/" + icon_image + (high_res ? "_30.png" : ".png");
1410  add_image(cfg, tc_base + "~RC(magenta>" + terrain_id + ")~BLIT(" + terrain_image + ")", terrain_name);
1411 }
1412 }
1413 
1414 REPORT_GENERATOR(terrain_info, rc)
1415 {
1416  const gamemap &map = rc.map();
1417  map_location mouseover_hex = rc.screen().mouseover_hex();
1418 
1419  if (!map.on_board(mouseover_hex))
1420  mouseover_hex = rc.screen().selected_hex();
1421 
1422  if (!map.on_board(mouseover_hex))
1423  return config();
1424 
1425  t_translation::terrain_code terrain = map.get_terrain(mouseover_hex);
1427  return config();
1428 
1429  config cfg;
1430 
1431  bool high_res = false;
1432 
1433  if (display::get_singleton()->shrouded(mouseover_hex)) {
1434  return cfg;
1435  }
1436  //TODO
1437 // if (display::get_singleton()->fogged(mouseover_hex)) {
1438 // blit_tced_icon(cfg, "fog", high_res);
1439 // }
1440 //
1441 // if (map.is_keep(mouseover_hex)) {
1442 // blit_tced_icon(cfg, "keep", high_res);
1443 // }
1444 
1445  const t_translation::ter_list& underlying_terrains = map.underlying_union_terrain(terrain);
1446  for (const t_translation::terrain_code& underlying_terrain : underlying_terrains) {
1447 
1449  continue;
1450  const std::string& terrain_id = map.get_terrain_info(underlying_terrain).id();
1451  const std::string& terrain_name = map.get_terrain_string(underlying_terrain);
1452  const std::string& terrain_icon = map.get_terrain_info(underlying_terrain).icon_image();
1453  if (terrain_icon.empty())
1454  continue;
1455  blit_tced_icon(cfg, terrain_id, terrain_icon, high_res, terrain_name);
1456  }
1457  return cfg;
1458 }
1459 
1461 {
1462  const gamemap &map = rc.map();
1463  int viewing_side = rc.screen().viewing_side();
1464  const team &viewing_team = rc.dc().get_team(viewing_side);
1465  map_location mouseover_hex = rc.screen().mouseover_hex();
1466  if (!map.on_board(mouseover_hex) || viewing_team.shrouded(mouseover_hex))
1467  return config();
1468 
1469  t_translation::terrain_code terrain = map.get_terrain(mouseover_hex);
1471  return config();
1472 
1473  std::ostringstream str;
1474  if (map.is_village(mouseover_hex))
1475  {
1476  int owner = rc.dc().village_owner(mouseover_hex) + 1;
1477  if (owner == 0 || viewing_team.fogged(mouseover_hex)) {
1478  str << map.get_terrain_info(terrain).income_description();
1479  } else if (owner == viewing_side) {
1480  str << map.get_terrain_info(terrain).income_description_own();
1481  } else if (viewing_team.is_enemy(owner)) {
1482  str << map.get_terrain_info(terrain).income_description_enemy();
1483  } else {
1484  str << map.get_terrain_info(terrain).income_description_ally();
1485  }
1486 
1487  const std::string& underlying_desc = map.get_underlying_terrain_string(terrain);
1488  if(!underlying_desc.empty()) {
1489  str << underlying_desc;
1490  }
1491  } else {
1492  str << map.get_terrain_string(terrain);
1493  }
1494 
1495  return text_report(str.str());
1496 }
1497 
1498 REPORT_GENERATOR(zoom_level, rc)
1499 {
1500  std::ostringstream text;
1501  std::ostringstream tooltip;
1502  std::ostringstream help;
1503 
1504  text << static_cast<int>(rc.screen().get_zoom_factor() * 100) << "%";
1505 
1506  return text_report(text.str(), tooltip.str(), help.str());
1507 }
1508 
1509 REPORT_GENERATOR(position, rc)
1510 {
1511  const gamemap &map = rc.map();
1512  map_location mouseover_hex = rc.screen().mouseover_hex(),
1513  displayed_unit_hex = rc.screen().displayed_unit_hex(),
1514  selected_hex = rc.screen().selected_hex();
1515 
1516  if (!map.on_board(mouseover_hex)) {
1517  if (!map.on_board(selected_hex))
1518  return config();
1519  else {
1520  mouseover_hex = selected_hex;
1521  }
1522  }
1523 
1524  t_translation::terrain_code terrain = map[mouseover_hex];
1526  return config();
1527 
1528  std::ostringstream str;
1529  str << mouseover_hex;
1530 
1531  const unit *u = get_visible_unit(rc);
1532  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1533  if (!u ||
1534  (displayed_unit_hex != mouseover_hex &&
1535  displayed_unit_hex != rc.screen().selected_hex()) ||
1536  viewing_team.shrouded(mouseover_hex))
1537  return text_report(str.str());
1538 
1539  int move_cost = u->movement_cost(terrain);
1540  int defense = 100 - u->defense_modifier(terrain);
1541  if (move_cost < movetype::UNREACHABLE) {
1542  str << " " << defense << "%," << move_cost;
1543  } else if (mouseover_hex == displayed_unit_hex) {
1544  str << " " << defense << "%,‒";
1545  } else {
1546  str << " ‒";
1547  }
1548  return text_report(str.str());
1549 }
1550 
1551 REPORT_GENERATOR(side_playing, rc)
1552 {
1553  const team &active_team = rc.teams()[rc.screen().playing_team()];
1554  std::string flag_icon = active_team.flag_icon();
1555  std::string old_rgb = game_config::flag_rgb;
1556  std::string new_rgb = team::get_side_color_id(rc.screen().playing_side());
1557  std::string mods = "~RC(" + old_rgb + ">" + new_rgb + ")";
1558  if (flag_icon.empty())
1559  flag_icon = game_config::images::flag_icon;
1560  return image_report(flag_icon + mods, active_team.side_name());
1561 }
1562 
1563 REPORT_GENERATOR(observers, rc)
1564 {
1565  const std::set<std::string> &observers = rc.screen().observers();
1566  if (observers.empty())
1567  return config();
1568 
1569  std::ostringstream str;
1570  str << _("Observers:") << '\n';
1571  for (const std::string &obs : observers) {
1572  str << obs << '\n';
1573  }
1574  return image_report(game_config::images::observer, str.str());
1575 }
1576 
1577 /* TODO unused
1578 REPORT_GENERATOR(selected_terrain)
1579 {
1580  const std::string selected_terrain = editor::get_selected_terrain();
1581  if (selected_terrain.empty())
1582  return config();
1583  else
1584  return text_report(selected_terrain);
1585 }
1586 */
1587 
1588 /* TODO this is unused
1589 REPORT_GENERATOR(edit_left_button_function)
1590 {
1591  const std::string left_button_function = editor::get_left_button_function();
1592  if (left_button_function.empty())
1593  return config();
1594  else
1595  return text_report(left_button_function);
1596 }
1597 */
1598 
1599 REPORT_GENERATOR(report_clock, /*rc*/)
1600 {
1601  config report;
1603 
1604  std::ostringstream ss;
1605 
1607  ? "%I:%M %p"
1608  : "%H:%M";
1609 
1610  std::time_t t = std::time(nullptr);
1611  ss << std::put_time(std::localtime(&t), format);
1612  add_text(report, ss.str(), _("Clock"));
1613 
1614  return report;
1615 }
1616 
1617 
1618 REPORT_GENERATOR(battery, /*rc*/)
1619 {
1620  config report;
1621 
1623  add_text(report, (boost::format("%.0f %%") % desktop::battery_info::get_battery_percentage()).str(), _("Battery"));
1624 
1625  return report;
1626 }
1627 
1628 REPORT_GENERATOR(report_countdown, rc)
1629 {
1630  int viewing_side = rc.screen().viewing_side();
1631  const team &viewing_team = rc.dc().get_team(viewing_side);
1632  int min, sec;
1633  if (viewing_team.countdown_time() == 0)
1634  return report_report_clock(rc);
1635  std::ostringstream str;
1636  sec = viewing_team.countdown_time() / 1000;
1637  char const *end = naps;
1638  if (viewing_side != rc.screen().playing_side())
1639  str << span_color(font::GRAY_COLOR);
1640  else if (sec < 60)
1641  str << "<span foreground=\"#c80000\">";
1642  else if (sec < 120)
1643  str << "<span foreground=\"#c8c800\">";
1644  else
1645  end = "";
1646  min = sec / 60;
1647  str << min << ':';
1648  sec = sec % 60;
1649  if (sec < 10) str << '0';
1650  str << sec << end;
1651  return text_report(str.str(), _("Turn Countdown") + "\n\n" + _("Countdown until your turn automatically ends."));
1652 }
1653 
1655 {
1656  dynamic_generators_[name].reset(g);
1657 }
1658 
1659 config reports::generate_report(const std::string &name, reports::context & rc, bool only_static)
1660 {
1661  if (!only_static) {
1662  dynamic_report_generators::const_iterator i = dynamic_generators_.find(name);
1663  if (i != dynamic_generators_.end())
1664  return i->second->generate(rc);
1665  }
1666  static_report_generators::const_iterator j = static_generators.find(name);
1667  if (j != static_generators.end())
1668  return j->second(rc);
1669  return config();
1670 }
1671 
1672 const std::set<std::string> &reports::report_list()
1673 {
1674  if (!all_reports_.empty()) return all_reports_;
1675  for (const static_report_generators::value_type &v : static_generators) {
1676  all_reports_.insert(v.first);
1677  }
1678  for (const dynamic_report_generators::value_type &v : dynamic_generators_) {
1679  all_reports_.insert(v.first);
1680  }
1681  return all_reports_;
1682 }
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:505
const t_translation::ter_list & underlying_union_terrain(const map_location &loc) const
Definition: map.cpp:58
std::string tod_dark
int get_max_liminal_bonus() const
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:1167
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:532
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:1312
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 get_current_time(const map_location &loc=map_location::null_location()) const
int under_leadership(const unit &u, const map_location &loc, const_attack_ptr weapon, const_attack_ptr opp_weapon)
Tests if the unit at loc is currently affected by leadership.
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:1672
static std::string format_hp(unsigned hp)
Definition: reports.cpp:912
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:876
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:900
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:2357
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
int generic_combat_modifier(int lawful_bonus, unit_type::ALIGNMENT alignment, bool is_fearless, int max_liminal_bonus)
Returns the amount that a unit&#39;s damage should be multiplied by due to a given lawful_bonus.
Definition: attack.cpp:1775
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:296
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:704
-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
static config tod_stats_at(reports::context &rc, const map_location &hex)
Definition: reports.cpp:1129
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
std::vector< std::tuple< std::string, t_string, t_string, t_string > > ability_tooltips() const
Gets the names and descriptions of this unit&#39;s abilities.
Definition: abilities.cpp:313
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
static config unit_abilities(const unit *u, const map_location &loc)
Definition: reports.cpp:398
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:1093
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:1598
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:91
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:360
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:343
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:1654
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:1155
color_t xp_color() const
Color for this unit&#39;s XP.
Definition: unit.cpp:1103
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:1659
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:95
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:720
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:452
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:712
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:1032
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:326
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:1219
bool invisible(const map_location &loc, bool see_all=true) const
Definition: unit.cpp:2385
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:639
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
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 std::vector< time_of_day > & times(const map_location &loc=map_location::null_location()) const
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:1666
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:906
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:884
const unit_race * race() const
Gets this unit&#39;s race.
Definition: unit.hpp:447
#define N_(String)
Definition: gettext.hpp:99
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:553
config & add_child(config_key_type key)
Definition: config.cpp:476
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...
std::vector< config > get_modification_advances() const
Gets any non-typed advanced options set by modifications.
Definition: unit.cpp:1723
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:919
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:1641
std::vector< std::pair< std::string, std::string > > amla_icons() const
Gets the image and description data for modification advancements.
Definition: unit.cpp:1706
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
std::shared_ptr< const attack_type > const_attack_ptr
Definition: ptr.hpp:37
static config unit_vision(const unit *u)
Definition: reports.cpp:618
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:2541
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:1755
const color_t inactive_ability_color