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