reports.cpp

Go to the documentation of this file.
00001 /* $Id: reports.cpp 53695 2012-03-30 15:42:21Z fendrin $ */
00002 /*
00003    Copyright (C) 2003 - 2012 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #include "global.hpp"
00017 
00018 #include "actions.hpp"
00019 #include "attack_prediction.hpp"
00020 #include "editor/editor_controller.hpp"
00021 #include "editor/palette/terrain_palettes.hpp"
00022 #include "font.hpp"
00023 #include "foreach.hpp"
00024 #include "game_display.hpp"
00025 #include "game_preferences.hpp"
00026 #include "gettext.hpp"
00027 #include "language.hpp"
00028 #include "map.hpp"
00029 #include "marked-up_text.hpp"
00030 #include "play_controller.hpp"
00031 #include "reports.hpp"
00032 #include "resources.hpp"
00033 #include "team.hpp"
00034 #include "text.hpp"
00035 #include "tod_manager.hpp"
00036 #include "unit.hpp"
00037 #include "whiteboard/manager.hpp"
00038 
00039 
00040 #include <cassert>
00041 #include <ctime>
00042 
00043 static void add_text(config &report, const std::string &text,
00044     const std::string &tooltip, const std::string &help = "")
00045 {
00046     config &element = report.add_child("element");
00047     element["text"] = text;
00048     if (!tooltip.empty()) element["tooltip"] = tooltip;
00049     if (!help.empty()) element["help"] = help;
00050 }
00051 
00052 static void add_image(config &report, const std::string &image,
00053     const std::string &tooltip, const std::string &help = "")
00054 {
00055     config &element = report.add_child("element");
00056     element["image"] = image;
00057     if (!tooltip.empty()) element["tooltip"] = tooltip;
00058     if (!help.empty()) element["help"] = help;
00059 }
00060 
00061 static config report()
00062 {
00063     return config();
00064 }
00065 
00066 static config text_report(const std::string &text,
00067     const std::string &tooltip = "", const std::string &help = "")
00068 {
00069     config r;
00070     add_text(r, text, tooltip, help);
00071     return r;
00072 }
00073 
00074 static config image_report(const std::string &image,
00075     const std::string &tooltip = "", const std::string &help = "")
00076 {
00077     config r;
00078     add_image(r, image, tooltip, help);
00079     return r;
00080 }
00081 
00082 using font::span_color;
00083 
00084 static void add_status(config &r,
00085     char const *path, char const *desc1, char const *desc2)
00086 {
00087     std::ostringstream s;
00088     s << gettext(desc1) << gettext(desc2);
00089     add_image(r, path, s.str());
00090 }
00091 
00092 static std::string flush(std::ostringstream &s)
00093 {
00094     std::string r(s.str());
00095     s.str(std::string());
00096     return r;
00097 }
00098 
00099 typedef config (*generator_function)();
00100 
00101 typedef std::map<std::string, generator_function> static_report_generators;
00102 typedef std::map<std::string, reports::generator *> dynamic_report_generators;
00103 static static_report_generators static_generators;
00104 static dynamic_report_generators dynamic_generators;
00105 
00106 struct report_generator_helper
00107 {
00108     report_generator_helper(const char *name, generator_function g)
00109     {
00110         static_generators.insert(static_report_generators::value_type(name, g));
00111     }
00112 };
00113 
00114 #define REPORT_GENERATOR(n) \
00115     static config report_##n(); \
00116     static report_generator_helper reg_gen_##n(#n, &report_##n); \
00117     static config report_##n()
00118 
00119 static char const *naps = "</span>";
00120 
00121 static unit *get_visible_unit()
00122 {
00123     return get_visible_unit(resources::screen->displayed_unit_hex(),
00124         (*resources::teams)[resources::screen->viewing_team()],
00125         resources::screen->show_everything());
00126 }
00127 
00128 static unit *get_selected_unit()
00129 {
00130     return get_visible_unit(resources::screen->selected_hex(),
00131         (*resources::teams)[resources::screen->viewing_team()],
00132         resources::screen->show_everything());
00133 }
00134 
00135 static config gray_inactive(const std::string &str)
00136 {
00137     if (resources::screen->viewing_side() == resources::screen->playing_side())
00138         return text_report(str);
00139     return text_report(span_color(font::GRAY_COLOR) + str + naps);
00140 }
00141 
00142 static config unit_name(unit *u)
00143 {
00144     if (!u) {
00145         return report();
00146     }
00147 
00148     /*
00149      * The name needs to be escaped, it might be set by the user and using
00150      * markup. Also names often contain a forbidden single quote.
00151      */
00152     const std::string& name = font::escape_text(u->name());
00153     std::ostringstream str, tooltip;
00154     str << "<b>" << name << "</b>";
00155     tooltip << _("Name: ") << "<b>" << name << "</b>";
00156     return text_report(str.str(), tooltip.str());
00157 }
00158 
00159 REPORT_GENERATOR(unit_name)
00160 {
00161     unit *u = get_visible_unit();
00162     return unit_name(u);
00163 }
00164 REPORT_GENERATOR(selected_unit_name)
00165 {
00166     unit *u = get_selected_unit();
00167     return unit_name(u);
00168 }
00169 
00170 static config unit_type(unit* u)
00171 {
00172     if (!u) return report();
00173     std::ostringstream str, tooltip;
00174     str << span_color(font::unit_type_color) << u->type_name() << naps;
00175     tooltip << _("Type: ") << "<b>" << u->type_name() << "</b>\n"
00176         << u->unit_description();
00177     return text_report(str.str(), tooltip.str(), "unit_" + u->type_id());
00178 }
00179 REPORT_GENERATOR(unit_type)
00180 {
00181     unit *u = get_visible_unit();
00182     return unit_type(u);
00183 }
00184 REPORT_GENERATOR(selected_unit_type)
00185 {
00186     unit *u = get_selected_unit();
00187     return unit_type(u);
00188 }
00189 
00190 static config unit_race(unit* u)
00191 {
00192     if (!u) return report();
00193     std::ostringstream str, tooltip;
00194     str << span_color(font::race_color) << u->race()->name(u->gender()) << naps;
00195     tooltip << _("Race: ") << "<b>" << u->race()->name(u->gender()) << "</b>";
00196     return text_report(str.str(), tooltip.str(), "..race_" + u->race()->id());
00197 }
00198 REPORT_GENERATOR(unit_race)
00199 {
00200     unit *u = get_visible_unit();
00201     return unit_race(u);
00202 }
00203 REPORT_GENERATOR(selected_unit_race)
00204 {
00205     unit *u = get_selected_unit();
00206     return unit_race(u);
00207 }
00208 
00209 static config unit_side(unit* u)
00210 {
00211     if (!u) return report();
00212     const team &u_team = (*resources::teams)[u->side() - 1];
00213     std::string flag_icon = u_team.flag_icon();
00214     std::string old_rgb = game_config::flag_rgb;
00215     std::string new_rgb = team::get_side_color_index(u->side());
00216     std::string mods = "~RC(" + old_rgb + ">" + new_rgb + ")";
00217     if (flag_icon.empty())
00218         flag_icon = game_config::images::flag_icon;
00219     return image_report(flag_icon + mods, u_team.current_player());
00220 }
00221 REPORT_GENERATOR(unit_side)
00222 {
00223     unit *u = get_visible_unit();
00224     return unit_side(u);
00225 }
00226 REPORT_GENERATOR(selected_unit_side)
00227 {
00228     unit *u = get_selected_unit();
00229     return unit_side(u);
00230 }
00231 
00232 static config unit_level(unit* u)
00233 {
00234     if (!u) return report();
00235     std::ostringstream str, tooltip;
00236     str << u->level();
00237     tooltip << _("Level: ") << "<b>" << u->level() << "</b>\n";
00238     const std::vector<std::string> &adv_to = u->advances_to_translated();
00239     if (adv_to.empty())
00240         tooltip << _("No advancement");
00241     else
00242         tooltip << _("Advances to:") << "\n<b>\t"
00243             << utils::join(adv_to, "\n\t") << "</b>";
00244     return text_report(str.str(), tooltip.str());
00245 }
00246 REPORT_GENERATOR(unit_level)
00247 {
00248     unit *u = get_visible_unit();
00249     return unit_level(u);
00250 }
00251 REPORT_GENERATOR(selected_unit_level)
00252 {
00253     unit *u = get_selected_unit();
00254     return unit_level(u);
00255 }
00256 
00257 REPORT_GENERATOR(unit_amla)
00258 {
00259     unit *u = get_visible_unit();
00260     if (!u) return report();
00261     config res;
00262     typedef std::pair<std::string, std::string> pair_string;
00263     foreach(const pair_string &ps, u->amla_icons()) {
00264         add_image(res, ps.first, ps.second);
00265     }
00266     return res;
00267 }
00268 
00269 static config unit_traits(unit* u)
00270 {
00271 
00272     if (!u) return report();
00273     config res;
00274     const std::vector<t_string> &traits = u->trait_names();
00275     const std::vector<t_string> &descriptions = u->trait_descriptions();
00276     unsigned nb = traits.size();
00277     for (unsigned i = 0; i < nb; ++i)
00278     {
00279         std::ostringstream str, tooltip;
00280         str << traits[i];
00281         if (i != nb - 1 ) str << ", ";
00282         tooltip << _("Trait: ") << "<b>" << traits[i] << "</b>\n"
00283             << descriptions[i];
00284         add_text(res, str.str(), tooltip.str());
00285     }
00286     return res;
00287 }
00288 REPORT_GENERATOR(unit_traits)
00289 {
00290     unit *u = get_visible_unit();
00291     return unit_traits(u);
00292 }
00293 REPORT_GENERATOR(selected_unit_traits)
00294 {
00295     unit *u = get_selected_unit();
00296     return unit_traits(u);
00297 }
00298 
00299 static config unit_status(unit* u)
00300 {
00301     if (!u) return report();
00302     config res;
00303     map_location displayed_unit_hex = resources::screen->displayed_unit_hex();
00304     if (resources::game_map->on_board(displayed_unit_hex) && u->invisible(displayed_unit_hex)) {
00305         add_status(res, "misc/invisible.png", N_("invisible: "),
00306             N_("This unit is invisible. It cannot be seen or attacked by enemy units."));
00307     }
00308     if (u->get_state(unit::STATE_SLOWED)) {
00309         add_status(res, "misc/slowed.png", N_("slowed: "),
00310             N_("This unit has been slowed. It will only deal half its normal damage when attacking and its movement cost is doubled."));
00311     }
00312     if (u->get_state(unit::STATE_POISONED)) {
00313         add_status(res, "misc/poisoned.png", N_("poisoned: "),
00314             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."));
00315     }
00316     if (u->get_state(unit::STATE_PETRIFIED)) {
00317         add_status(res, "misc/petrified.png", N_("petrified: "),
00318             N_("This unit has been petrified. It may not move or attack."));
00319     }
00320     return res;
00321 }
00322 REPORT_GENERATOR(unit_status)
00323 {
00324     unit *u = get_visible_unit();
00325     return unit_status(u);
00326 }
00327 REPORT_GENERATOR(selected_unit_status)
00328 {
00329     unit *u = get_selected_unit();
00330     return unit_status(u);
00331 }
00332 
00333 static config unit_alignment(unit* u)
00334 {
00335     if (!u) return report();
00336     std::ostringstream str, tooltip;
00337     char const *align = unit_type::alignment_description(u->alignment(), u->gender());
00338     std::string align_id = unit_type::alignment_id(u->alignment());
00339     int cm = combat_modifier(resources::screen->displayed_unit_hex(), u->alignment(), u->is_fearless());
00340     str << align << " (" << utils::signed_percent(cm) << ")";
00341     tooltip << _("Alignment: ") << "<b>" << align << "</b>\n"
00342         << string_table[align_id + "_description"];
00343     return text_report(str.str(), tooltip.str(), "time_of_day");
00344 }
00345 REPORT_GENERATOR(unit_alignment)
00346 {
00347     unit *u = get_visible_unit();
00348     return unit_alignment(u);
00349 }
00350 REPORT_GENERATOR(selected_unit_alignment)
00351 {
00352     unit *u = get_selected_unit();
00353     return unit_alignment(u);
00354 }
00355 
00356 
00357 static config unit_abilities(unit* u)
00358 {
00359     if (!u) return report();
00360     config res;
00361     const std::vector<boost::tuple<t_string,t_string,t_string> > &abilities = u->ability_tooltips();
00362     for (std::vector<boost::tuple<t_string,t_string,t_string> >::const_iterator i = abilities.begin(),
00363          i_end = abilities.end(); i != i_end; ++i)
00364     {
00365         std::ostringstream str, tooltip;
00366         const std::string &name = i->get<0>().base_str();
00367         str << i->get<1>().str();
00368         if (i + 1 != i_end) str << ", ";
00369         tooltip << _("Ability: ") << i->get<2>().str();
00370         add_text(res, str.str(), tooltip.str(), "ability_" + name);
00371     }
00372     return res;
00373 }
00374 REPORT_GENERATOR(unit_abilities)
00375 {
00376     unit *u = get_visible_unit();
00377     return unit_abilities(u);
00378 }
00379 REPORT_GENERATOR(selected_unit_abilities)
00380 {
00381     unit *u = get_selected_unit();
00382     return unit_abilities(u);
00383 }
00384 
00385 
00386 static config unit_hp(unit* u)
00387 {
00388     if (!u) return report();
00389     std::ostringstream str, tooltip;
00390     str << span_color(u->hp_color()) << u->hitpoints()
00391         << '/' << u->max_hitpoints() << naps;
00392 
00393     std::set<std::string> resistances_table;
00394     utils::string_map resistances = u->get_base_resistances();
00395 
00396     bool att_def_diff = false;
00397     map_location displayed_unit_hex = resources::screen->displayed_unit_hex();
00398     foreach (const utils::string_map::value_type &resist, u->get_base_resistances())
00399     {
00400         std::ostringstream line;
00401         line << gettext(resist.first.c_str()) << ": ";
00402         // Some units have different resistances when attacking or defending.
00403         int res_att = 100 - u->resistance_against(resist.first, true, displayed_unit_hex);
00404         int res_def = 100 - u->resistance_against(resist.first, false, displayed_unit_hex);
00405         if (res_att == res_def) {
00406             line << utils::signed_percent(res_def) << "\n";
00407         } else {
00408             line << utils::signed_percent(res_att) << " / " << utils::signed_percent(res_def) << '\n';
00409             att_def_diff = true;
00410         }
00411         resistances_table.insert(line.str());
00412     }
00413 
00414     tooltip << _("Resistances: ");
00415     if (att_def_diff)
00416         tooltip << _("(Att / Def)");
00417     tooltip << '\n';
00418     foreach (const std::string &line, resistances_table) {
00419         tooltip << line;
00420     }
00421     return text_report(str.str(), tooltip.str());
00422 }
00423 REPORT_GENERATOR(unit_hp)
00424 {
00425     unit *u = get_visible_unit();
00426     return unit_hp(u);
00427 }
00428 REPORT_GENERATOR(selected_unit_hp)
00429 {
00430     unit *u = get_selected_unit();
00431     return unit_hp(u);
00432 }
00433 
00434 static config unit_xp(unit* u)
00435 {
00436     if (!u) return report();
00437     std::ostringstream str, tooltip;
00438     str << span_color(u->xp_color()) << u->experience()
00439         << '/' << u->max_experience() << naps;
00440 
00441     int exp_mod = unit_type::experience_accelerator::get_acceleration();
00442     tooltip << _("Experience Modifier: ") << exp_mod << '%';
00443     return text_report(str.str(), tooltip.str());
00444 }
00445 REPORT_GENERATOR(unit_xp)
00446 {
00447     unit *u = get_visible_unit();
00448     return unit_xp(u);
00449 }
00450 REPORT_GENERATOR(selected_unit_xp)
00451 {
00452     unit *u = get_selected_unit();
00453     return unit_xp(u);
00454 }
00455 
00456 static config unit_advancement_options(unit* u)
00457 {
00458     if (!u) return report();
00459     config res;
00460     typedef std::pair<std::string, std::string> pair_string;
00461     foreach (const pair_string &ps, u->advancement_icons()) {
00462         add_image(res, ps.first, ps.second);
00463     }
00464     return res;
00465 }
00466 REPORT_GENERATOR(unit_advancement_options)
00467 {
00468     unit *u = get_visible_unit();
00469     return unit_advancement_options(u);
00470 }
00471 REPORT_GENERATOR(selected_unit_advancement_options)
00472 {
00473     unit *u = get_selected_unit();
00474     return unit_advancement_options(u);
00475 }
00476 
00477 static config unit_defense(unit* u, const map_location& displayed_unit_hex)
00478 {
00479     if(!u) {
00480         return report();
00481     }
00482 
00483     std::ostringstream str, tooltip;
00484     const gamemap &map = *resources::game_map;
00485     if(!resources::game_map->on_board(displayed_unit_hex)) {
00486         return report();
00487     }
00488 
00489     const t_translation::t_terrain &terrain = map[displayed_unit_hex];
00490     int def = 100 - u->defense_modifier(terrain);
00491     SDL_Color color = int_to_color(game_config::red_to_green(def));
00492     str << span_color(color) << def << "%</span>";
00493     tooltip << _("Terrain: ") << "<b>" << map.get_terrain_info(terrain).description() << "</b>\n";
00494 
00495     const t_translation::t_list &underlyings = map.underlying_def_terrain(terrain);
00496     std::vector<int> t_defs;
00497     bool revert = false;
00498     if (underlyings.size() != 1 || underlyings.front() != terrain)
00499     {
00500         foreach (const t_translation::t_terrain &t, underlyings)
00501         {
00502             if (t == t_translation::MINUS) {
00503                 revert = true;
00504             } else if (t == t_translation::PLUS) {
00505                 revert = false;
00506             } else {
00507                 int t_def = 100 - u->defense_modifier(t);
00508                 SDL_Color color = int_to_color(game_config::red_to_green(t_def));
00509                 tooltip << '\t' << map.get_terrain_info(t).description() << ": "
00510                     << span_color(color) << t_def << "%</span> "
00511                     << (revert ? _("maximum^max.") : _("minimum^min.")) << '\n';
00512             }
00513         }
00514     }
00515 
00516         tooltip << "<b>" << _("Defense: ") << span_color(color)  << def << "%</span></b>";
00517     return text_report(str.str(), tooltip.str());
00518 }
00519 REPORT_GENERATOR(unit_defense)
00520 {
00521     unit *u = get_visible_unit();
00522     const map_location& displayed_unit_hex = resources::screen->displayed_unit_hex();
00523     return unit_defense(u, displayed_unit_hex);
00524 }
00525 REPORT_GENERATOR(selected_unit_defense)
00526 {
00527     unit *u = get_selected_unit();
00528     const map_location& selected_hex = resources::screen->selected_hex();
00529     return unit_defense(u, selected_hex);
00530 }
00531 
00532 static config unit_moves(unit* u)
00533 {
00534     if (!u) return report();
00535     std::ostringstream str;
00536     double movement_frac = 1.0;
00537     if (u->side() == resources::screen->playing_side()) {
00538         movement_frac = double(u->movement_left()) / std::max<int>(1, u->total_movement());
00539         if (movement_frac > 1.0)
00540             movement_frac = 1.0;
00541     }
00542 
00543     int grey = 128 + int((255 - 128) * movement_frac);
00544     SDL_Color c = create_color(grey, grey, grey);
00545     str << span_color(c) << u->movement_left() << '/' << u->total_movement() << naps;
00546     return text_report(str.str());
00547 }
00548 REPORT_GENERATOR(unit_moves)
00549 {
00550     unit *u = get_visible_unit();
00551     return unit_moves(u);
00552 }
00553 REPORT_GENERATOR(selected_unit_moves)
00554 {
00555     unit *u = get_selected_unit();
00556     return unit_moves(u);
00557 }
00558 
00559 static int attack_info(const attack_type &at, config &res, unit *u, const map_location &displayed_unit_hex)
00560 {
00561     std::ostringstream str, tooltip;
00562 
00563     at.set_specials_context(displayed_unit_hex, map_location(), *u);
00564     int base_damage = at.damage();
00565     int damage_multiplier = 100;
00566     int tod_bonus = combat_modifier(displayed_unit_hex, u->alignment(), u->is_fearless());
00567     damage_multiplier += tod_bonus;
00568     int leader_bonus = 0;
00569     if (under_leadership(*resources::units, displayed_unit_hex, &leader_bonus).valid())
00570         damage_multiplier += leader_bonus;
00571 
00572     // Assume no specific resistance.
00573     damage_multiplier *= 100;
00574     bool slowed = u->get_state(unit::STATE_SLOWED);
00575     int damage_divisor = slowed ? 20000 : 10000;
00576     int damage = round_damage(base_damage, damage_multiplier, damage_divisor);
00577 
00578     int base_nattacks = at.num_attacks();
00579     int nattacks = base_nattacks;
00580     unit_ability_list swarm = at.get_specials("swarm");
00581     if (!swarm.empty())
00582     {
00583         int swarm_max_attacks = swarm.highest("swarm_attacks_max", nattacks).first;
00584         int swarm_min_attacks = swarm.highest("swarm_attacks_min").first;
00585         int hitp = u->hitpoints();
00586         int mhitp = u->max_hitpoints();
00587         nattacks = swarm_min_attacks + (swarm_max_attacks - swarm_min_attacks) * hitp / mhitp;
00588     }
00589     SDL_Color dmg_color = font::weapon_color;
00590     double dmg_bonus = double(damage) / base_damage;
00591     if (dmg_bonus > 1.0)
00592         dmg_color = font::good_dmg_color;
00593     else if (dmg_bonus < 1.0)
00594         dmg_color = font::bad_dmg_color;
00595 
00596     str << span_color(dmg_color) << damage << naps << span_color(font::weapon_color)
00597         << font::weapon_numbers_sep << nattacks << ' ' << at.name()
00598         << "</span>\n";
00599     tooltip << _("Weapon: ") << "<b>" << at.name() << "</b>\n"
00600         << _("Damage: ") << "<b>" << damage << "</b>\n";
00601 
00602     if (tod_bonus || leader_bonus || slowed)
00603     {
00604         tooltip << '\t' << _("Base damage: ") << base_damage << '\n';
00605         if (tod_bonus) {
00606             tooltip << '\t' << _("Time of day: ")
00607                 << utils::signed_percent(tod_bonus) << '\n';
00608         }
00609         if (leader_bonus) {
00610             tooltip << '\t' << _("Leadership: ")
00611                 << utils::signed_percent(leader_bonus) << '\n';
00612         }
00613         if (slowed) {
00614             tooltip << '\t' << _("Slowed: ") << "/ 2" << '\n';
00615         }
00616     }
00617 
00618     tooltip << _("Attacks: ") << "<b>" << nattacks << "</b>\n";
00619     if (nattacks != base_nattacks){
00620         tooltip << '\t' << _("Base attacks: ") << base_nattacks << '\n';
00621         int hp_ratio = u->hitpoints() * 100 / u->max_hitpoints();
00622         tooltip << '\t' << _("Swarm: ") << "* "<< hp_ratio << "%\n";
00623     }
00624 
00625     add_text(res, flush(str), flush(tooltip));
00626 
00627     std::string range = string_table["range_" + at.range()];
00628     std::string lang_type = string_table["type_" + at.type()];
00629 
00630     str << span_color(font::weapon_details_color) << "  "
00631         << range << font::weapon_details_sep
00632         << lang_type << "</span>\n";
00633 
00634     tooltip << _("Weapon range: ") << "<b>" << range << "</b>\n"
00635         << _("Damage type: ")  << "<b>" << lang_type << "</b>\n"
00636         << _("Damage versus: ") << '\n';
00637 
00638     // Show this weapon damage and resistance against all the different units.
00639     // We want weak resistances (= good damage) first.
00640     std::map<int, std::set<std::string>, std::greater<int> > resistances;
00641     std::set<std::string> seen_types;
00642     const team &unit_team = (*resources::teams)[u->side() - 1];
00643     const team &viewing_team = (*resources::teams)[resources::screen->viewing_team()];
00644     foreach(const unit &enemy, *resources::units)
00645     {
00646         if (!unit_team.is_enemy(enemy.side()))
00647             continue;
00648         const map_location &loc = enemy.get_location();
00649         if (viewing_team.fogged(loc) ||
00650             (viewing_team.is_enemy(enemy.side()) && enemy.invisible(loc)))
00651             continue;
00652         bool new_type = seen_types.insert(enemy.type_id()).second;
00653         if (new_type) {
00654             int resistance = enemy.resistance_against(at, false, loc);
00655             resistances[resistance].insert(enemy.type_name());
00656         }
00657     }
00658 
00659     // Get global ToD.
00660     damage_multiplier = 100;
00661     tod_bonus = combat_modifier(map_location::null_location, u->alignment(), u->is_fearless());
00662     damage_multiplier += tod_bonus;
00663 
00664     typedef std::pair<int, std::set<std::string> > resist_units;
00665     foreach (const resist_units &resist, resistances) {
00666         int damage = round_damage(base_damage, damage_multiplier * resist.first, damage_divisor);
00667         tooltip << "<b>" << damage << "</b>  "
00668             << "<i>(" << utils::signed_percent(resist.first-100) << ")</i> : "
00669             << utils::join(resist.second, ", ") << '\n';
00670     }
00671     add_text(res, flush(str), flush(tooltip));
00672 
00673     const std::string &accuracy_parry = at.accuracy_parry_description();
00674     if (!accuracy_parry.empty())
00675     {
00676         str << span_color(font::weapon_details_color)
00677             << "  " << accuracy_parry << "</span>\n";
00678         int accuracy = at.accuracy();
00679         if (accuracy) {
00680             tooltip << _("Accuracy:") << "<b>"
00681                 << utils::signed_percent(accuracy) << "</b>\n";
00682         }
00683         int parry = at.parry();
00684         if (parry) {
00685             tooltip << _("Parry:") << "<b>"
00686                 << utils::signed_percent(parry) << "</b>\n";
00687             }
00688         add_text(res, flush(str), flush(tooltip));
00689     }
00690 
00691     const std::vector<t_string> &specials = at.special_tooltips();
00692     if (!specials.empty())
00693     {
00694         for (std::vector<t_string>::const_iterator sp_it = specials.begin(),
00695              sp_end = specials.end(); sp_it != sp_end; ++sp_it)
00696         {
00697             str << span_color(font::weapon_details_color)
00698                 << "  " << *sp_it << "</span>\n";
00699             std::string help_page = "weaponspecial_" + sp_it->base_str();
00700             ++sp_it;
00701             //FIXME pull out special's name from description
00702             tooltip << _("Weapon special: ") << *sp_it << '\n';
00703             add_text(res, flush(str), flush(tooltip), help_page);
00704         }
00705     }
00706     return damage;
00707 }
00708 
00709 // Conversion routine for both unscathed and damage change percentage.
00710 static void format_prob(char str_buf[10], double prob)
00711 {
00712 
00713     if(prob > 0.9995) {
00714         snprintf(str_buf, 10, "100 %%");
00715     } else if(prob >= 0.1) {
00716         snprintf(str_buf, 10, "%4.1f %%", 100.0 * prob);
00717     } else {
00718         snprintf(str_buf, 10, " %3.1f %%", 100.0 * prob);
00719     }
00720 
00721     str_buf[9] = '\0';  //prevents _snprintf error
00722 }
00723 
00724 static void format_hp(char str_buf[10], int hp)
00725 {
00726     if(hp < 10) {
00727         snprintf(str_buf, 10, "   %i", hp);
00728     } else if(hp < 99) {
00729         snprintf(str_buf, 10, "  %i", hp);
00730     } else if(hp < 999) {
00731         snprintf(str_buf, 10, " %i", hp);
00732     } else {
00733         snprintf(str_buf, 10, " %i", hp);
00734     }
00735 
00736     str_buf[9] = '\0';  //prevents _snprintf error
00737 }
00738 
00739 static config unit_weapons(unit *attacker, const map_location &attacker_pos, unit *defender, bool show_attacker)
00740 {
00741     if (!attacker || !defender) return report();
00742 
00743     unit* u = show_attacker ? attacker : defender;
00744     const map_location unit_loc = show_attacker ? attacker_pos : defender->get_location();
00745 
00746     std::ostringstream str, tooltip;
00747     config res;
00748 
00749     std::vector<battle_context> weapons;
00750     for (unsigned int i = 0; i < attacker->attacks().size(); i++) {
00751         // skip weapons with attack_weight=0
00752         if (attacker->attacks()[i].attack_weight() > 0) {
00753             battle_context weapon(*resources::units, attacker_pos, defender->get_location(), i, -1, 0.0, NULL, attacker);
00754             weapons.push_back(weapon);
00755         }
00756     }
00757 
00758     foreach(const battle_context& weapon, weapons) {
00759 
00760         // Predict the battle outcome.
00761         combatant attacker_combatant(weapon.get_attacker_stats());
00762         combatant defender_combatant(weapon.get_defender_stats());
00763         attacker_combatant.fight(defender_combatant);
00764 
00765         const battle_context_unit_stats& context_unit_stats =
00766                 show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
00767 
00768         int total_damage = 0;
00769         int base_damage = 0;
00770         int num_blows = 0;
00771         int chance_to_hit = 0;
00772         t_string weapon_name = _("None");
00773 
00774         SDL_Color dmg_color = font::weapon_color;
00775         if (context_unit_stats.weapon) {
00776             base_damage = attack_info(*context_unit_stats.weapon, res, u, unit_loc);
00777             total_damage = context_unit_stats.damage;
00778             num_blows = context_unit_stats.num_blows;
00779             chance_to_hit = context_unit_stats.chance_to_hit;
00780             weapon_name = context_unit_stats.weapon->name();
00781 
00782             double dmg_bonus = double(total_damage) / base_damage;
00783             if (dmg_bonus > 1.0)
00784                 dmg_color = font::good_dmg_color;
00785             else if (dmg_bonus < 1.0)
00786                 dmg_color = font::bad_dmg_color;
00787         } else {
00788             str << span_color(font::weapon_color) << weapon_name << naps << "\n";
00789             tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
00790                 << _("Damage: ") << "<b>" << "0" << "</b>\n";
00791         }
00792 
00793         SDL_Color chance_color = int_to_color(game_config::red_to_green(chance_to_hit));
00794 
00795         // Total damage.
00796         str << "  " << span_color(dmg_color) << total_damage << naps << span_color(font::weapon_color)
00797             << utils::unicode_en_dash << num_blows
00798             << " (" << span_color(chance_color) << chance_to_hit << "%" << naps << ")"
00799             << naps << "\n";
00800 
00801         tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
00802                 << _("Total damage") << "<b>" << total_damage << "</b>\n";
00803 
00804         // Create the hitpoints distribution.
00805         std::vector<std::pair<int, double> > hp_prob_vector;
00806 
00807         // First, we sort the probabilities in ascending order.
00808         std::vector<std::pair<double, int> > prob_hp_vector;
00809         int i;
00810 
00811         combatant* c = show_attacker ? &attacker_combatant : &defender_combatant;
00812 
00813         for(i = 0; i < static_cast<int>(c->hp_dist.size()); i++) {
00814             double prob = c->hp_dist[i];
00815 
00816             // We keep only values above 0.1%.
00817             if(prob > 0.001)
00818                 prob_hp_vector.push_back(std::pair<double, int>(prob, i));
00819         }
00820 
00821         std::sort(prob_hp_vector.begin(), prob_hp_vector.end());
00822 
00823         //TODO fendrin -- make that dynamically
00824         int max_hp_distrib_rows_ = 10;
00825 
00826         // We store a few of the highest probability hitpoint values.
00827         int nb_elem = std::min<int>(max_hp_distrib_rows_, prob_hp_vector.size());
00828 
00829         for(i = prob_hp_vector.size() - nb_elem;
00830                 i < static_cast<int>(prob_hp_vector.size()); i++) {
00831 
00832             hp_prob_vector.push_back(std::pair<int, double>
00833             (prob_hp_vector[i].second, prob_hp_vector[i].first));
00834         }
00835 
00836         // Then, we sort the hitpoint values in ascending order.
00837         std::sort(hp_prob_vector.begin(), hp_prob_vector.end());
00838         // And reverse the order. Might be doable in a better manor.
00839         std::reverse(hp_prob_vector.begin(), hp_prob_vector.end());
00840 
00841         for(i = 0;
00842                 i < static_cast<int>(hp_prob_vector.size()); i++) {
00843 
00844             int hp = hp_prob_vector[i].first;
00845             double prob = hp_prob_vector[i].second;
00846 
00847             char prob_buf[10];
00848             format_prob(prob_buf, prob);
00849             char hp_buf[10];
00850             format_hp(hp_buf, hp);
00851 
00852             SDL_Color prob_color = int_to_color(game_config::blue_to_white(prob * 100.0, true));
00853 
00854             str     << span_color(font::weapon_details_color) << "  " << "  "
00855                     << span_color(u->hp_color(hp)) << hp_buf << naps
00856                     << " " << font::weapon_numbers_sep << " "
00857                     << span_color(prob_color) << prob_buf << naps
00858                     << naps << "\n";
00859         }
00860 
00861         add_text(res, flush(str), flush(tooltip));
00862     }
00863     return res;
00864 }
00865 
00866 static config unit_weapons(unit *u)
00867 {
00868     if (!u) return report();
00869     map_location displayed_unit_hex = resources::screen->displayed_unit_hex();
00870     config res;
00871 
00872     foreach (const attack_type &at, u->attacks())
00873     {
00874         attack_info(at, res, u, displayed_unit_hex);
00875     }
00876     return res;
00877 }
00878 REPORT_GENERATOR(unit_weapons)
00879 {
00880     unit *u = get_visible_unit();
00881     if (!u) return config();
00882 
00883     return unit_weapons(u);
00884 }
00885 REPORT_GENERATOR(highlighted_unit_weapons)
00886 {
00887     unit *u = get_selected_unit();
00888     unit *sec_u = get_visible_unit();
00889 
00890     if (!u) return config();
00891     if (!sec_u || u == sec_u) return unit_weapons(sec_u);
00892 
00893     map_location highlighted_hex = resources::screen->displayed_unit_hex();
00894     map_location attack_loc =
00895             resources::controller->get_mouse_handler_base().current_unit_attacks_from(highlighted_hex);
00896 
00897     if (!attack_loc.valid())
00898         return unit_weapons(sec_u);
00899 
00900     return unit_weapons(u, attack_loc, sec_u, false);
00901 }
00902 REPORT_GENERATOR(selected_unit_weapons)
00903 {
00904     unit *u = get_selected_unit();
00905     unit *sec_u = get_visible_unit();
00906 
00907     if (!u) return config();
00908     if (!sec_u || u == sec_u) return unit_weapons(u);
00909 
00910     map_location highlighted_hex = resources::screen->displayed_unit_hex();
00911     map_location attack_loc =
00912             resources::controller->get_mouse_handler_base().current_unit_attacks_from(highlighted_hex);
00913 
00914     if (!attack_loc.valid())
00915         return unit_weapons(u);
00916 
00917     return unit_weapons(u, attack_loc, sec_u, true);
00918 }
00919 
00920 REPORT_GENERATOR(unit_image)
00921 {
00922     unit *u = get_visible_unit();
00923     if (!u) return report();
00924     return image_report(u->absolute_image() + u->image_mods());
00925 }
00926 REPORT_GENERATOR(selected_unit_image)
00927 {
00928     unit *u = get_selected_unit();
00929     if (!u) return report();
00930     return image_report(u->absolute_image() + u->image_mods());
00931 }
00932 
00933 REPORT_GENERATOR(selected_unit_profile)
00934 {
00935     unit *u = get_selected_unit();
00936     if (!u) return report();
00937     return image_report(u->small_profile());
00938 }
00939 REPORT_GENERATOR(unit_profile)
00940 {
00941     unit *u = get_visible_unit();
00942     if (!u) return report();
00943     return image_report(u->small_profile());
00944 }
00945 
00946 static config time_of_day_at(map_location& mouseover_hex)
00947 {
00948     std::ostringstream tooltip;
00949     time_of_day tod;
00950     const team &viewing_team = (*resources::teams)[resources::screen->viewing_team()];
00951     if (viewing_team.shrouded(mouseover_hex)) {
00952         // Don't show time on shrouded tiles.
00953         tod = resources::tod_manager->get_time_of_day();
00954     } else if (viewing_team.fogged(mouseover_hex)) {
00955         // Don't show illuminated time on fogged tiles.
00956         tod = resources::tod_manager->get_time_of_day(mouseover_hex);
00957     } else {
00958         tod = resources::tod_manager->get_illuminated_time_of_day(mouseover_hex);
00959     }
00960 
00961     int b = tod.lawful_bonus;
00962 
00963     tooltip << tod.name << '\n'
00964         << _("Lawful units: ") << utils::signed_percent(b) << '\n'
00965         << _("Neutral units: ") << utils::signed_percent(0) << '\n'
00966         << _("Chaotic units: ") << utils::signed_percent(-b) << '\n'
00967         << _("Liminal units: ") << utils::signed_percent(-(abs(b)));
00968 
00969     std::string tod_image = tod.image;
00970     if (tod.bonus_modified > 0) tod_image += "~BRIGHTEN()";
00971     else if (tod.bonus_modified < 0) tod_image += "~DARKEN()";
00972     if (preferences::flip_time()) tod_image += "~FL(horiz)";
00973 
00974     return image_report(tod_image, tooltip.str(), "time_of_day");
00975 }
00976 REPORT_GENERATOR(time_of_day)
00977 {
00978     map_location mouseover_hex = resources::screen->mouseover_hex();
00979     return time_of_day_at(mouseover_hex);
00980 }
00981 REPORT_GENERATOR(selected_time_of_day)
00982 {
00983     map_location selected_hex = resources::screen->selected_hex();
00984     return time_of_day_at(selected_hex);
00985 }
00986 
00987 REPORT_GENERATOR(turn)
00988 {
00989     std::ostringstream str;
00990     str << resources::tod_manager->turn();
00991     int nb = resources::tod_manager->number_of_turns();
00992     if (nb != -1) str << '/' << nb;
00993     return text_report(str.str());
00994 }
00995 
00996 REPORT_GENERATOR(gold)
00997 {
00998     std::ostringstream str;
00999     int viewing_side = resources::screen->viewing_side();
01000     // Suppose the full unit map is applied.
01001     int fake_gold = (*resources::teams)[viewing_side - 1].gold() -
01002         resources::whiteboard->get_spent_gold_for(viewing_side);
01003     char const *end = naps;
01004     if (viewing_side != resources::screen->playing_side()) {
01005         str << span_color(font::GRAY_COLOR);
01006     }
01007     else if (fake_gold < 0) {
01008         str << span_color(font::BAD_COLOR);
01009     }
01010     else {
01011         end = "";
01012     }
01013     str << utils::half_signed_value(fake_gold) << end;
01014     return text_report(str.str());
01015 }
01016 
01017 REPORT_GENERATOR(villages)
01018 {
01019     std::ostringstream str;
01020     int viewing_side = resources::screen->viewing_side();
01021     const team &viewing_team = (*resources::teams)[viewing_side - 1];
01022     team_data td = calculate_team_data(viewing_team, viewing_side);
01023     str << td.villages << '/';
01024     if (viewing_team.uses_shroud()) {
01025         int unshrouded_villages = 0;
01026         foreach (const map_location &loc, resources::game_map->villages()) {
01027             if (!viewing_team.shrouded(loc))
01028                 ++unshrouded_villages;
01029         }
01030         str << unshrouded_villages;
01031     } else {
01032         str << resources::game_map->villages().size();
01033     }
01034     return gray_inactive(str.str());
01035 }
01036 
01037 REPORT_GENERATOR(num_units)
01038 {
01039     return gray_inactive(str_cast(side_units(resources::screen->viewing_side())));
01040 }
01041 
01042 REPORT_GENERATOR(upkeep)
01043 {
01044     std::ostringstream str;
01045     int viewing_side = resources::screen->viewing_side();
01046     const team &viewing_team = (*resources::teams)[viewing_side - 1];
01047     team_data td = calculate_team_data(viewing_team, viewing_side);
01048     str << td.expenses << " (" << td.upkeep << ")";
01049     return gray_inactive(str.str());
01050 }
01051 
01052 REPORT_GENERATOR(expenses)
01053 {
01054     int viewing_side = resources::screen->viewing_side();
01055     const team &viewing_team = (*resources::teams)[viewing_side - 1];
01056     team_data td = calculate_team_data(viewing_team, resources::screen->viewing_side());
01057     return gray_inactive(str_cast(td.expenses));
01058 }
01059 
01060 REPORT_GENERATOR(income)
01061 {
01062     std::ostringstream str;
01063     int viewing_side = resources::screen->viewing_side();
01064     const team &viewing_team = (*resources::teams)[viewing_side - 1];
01065     team_data td = calculate_team_data(viewing_team, viewing_side);
01066     char const *end = naps;
01067     if (viewing_side != resources::screen->playing_side()) {
01068         if (td.net_income < 0) {
01069             td.net_income = - td.net_income;
01070             str << span_color(font::GRAY_COLOR);
01071             str << utils::unicode_minus;
01072         }
01073         else {
01074             str << span_color(font::GRAY_COLOR);
01075         }
01076     }
01077     else if (td.net_income < 0) {
01078         td.net_income = - td.net_income;
01079         str << span_color(font::BAD_COLOR);
01080         str << utils::unicode_minus;
01081     }
01082     else {
01083         end = "";
01084     }
01085     str << td.net_income << end;
01086     return text_report(str.str());
01087 }
01088 
01089 REPORT_GENERATOR(terrain)
01090 {
01091     gamemap &map = *resources::game_map;
01092     int viewing_side = resources::screen->viewing_side();
01093     const team &viewing_team = (*resources::teams)[viewing_side - 1];
01094     map_location mouseover_hex = resources::screen->mouseover_hex();
01095     if (!map.on_board(mouseover_hex) || viewing_team.shrouded(mouseover_hex))
01096         return report();
01097 
01098     t_translation::t_terrain terrain = map.get_terrain(mouseover_hex);
01099     if (terrain == t_translation::OFF_MAP_USER)
01100         return report();
01101 
01102     std::ostringstream str;
01103     if (map.is_village(mouseover_hex))
01104     {
01105         int owner = village_owner(mouseover_hex, *resources::teams) + 1;
01106         if (owner == 0 || viewing_team.fogged(mouseover_hex)) {
01107             str << map.get_terrain_info(terrain).income_description();
01108         } else if (owner == viewing_side) {
01109             str << map.get_terrain_info(terrain).income_description_own();
01110         } else if (viewing_team.is_enemy(owner)) {
01111             str << map.get_terrain_info(terrain).income_description_enemy();
01112         } else {
01113             str << map.get_terrain_info(terrain).income_description_ally();
01114         }
01115 
01116         const std::string& underlying_desc = map.get_underlying_terrain_string(terrain);
01117         if(!underlying_desc.empty()) {
01118             str << underlying_desc;
01119         }
01120     } else {
01121         str << map.get_terrain_string(terrain);
01122     }
01123 
01124     return text_report(str.str());
01125 }
01126 
01127 REPORT_GENERATOR(position)
01128 {
01129     gamemap &map = *resources::game_map;
01130     map_location mouseover_hex = resources::screen->mouseover_hex(),
01131         displayed_unit_hex = resources::screen->displayed_unit_hex();
01132     if (!map.on_board(mouseover_hex))
01133         return report();
01134     t_translation::t_terrain terrain = map[mouseover_hex];
01135     if (terrain == t_translation::OFF_MAP_USER)
01136         return report();
01137 
01138     std::ostringstream str;
01139     str << mouseover_hex;
01140 
01141     const unit *u = get_visible_unit();
01142     const team &viewing_team = (*resources::teams)[resources::screen->viewing_team()];
01143     if (!u ||
01144         (displayed_unit_hex != mouseover_hex &&
01145          displayed_unit_hex != resources::screen->selected_hex()) ||
01146         viewing_team.shrouded(mouseover_hex))
01147         return text_report(str.str());
01148 
01149     int move_cost = u->movement_cost(terrain);
01150     int defense = 100 - u->defense_modifier(terrain);
01151     if (move_cost < unit_movement_type::UNREACHABLE) {
01152         str << " (" << defense << "%," << move_cost << ')';
01153     } else if (mouseover_hex == displayed_unit_hex) {
01154         str << " (" << defense << "%,‒)";
01155     } else {
01156         str << " (‒)";
01157     }
01158     return text_report(str.str());
01159 }
01160 
01161 REPORT_GENERATOR(side_playing)
01162 {
01163     const team &active_team = (*resources::teams)[resources::screen->playing_team()];
01164     std::string flag_icon = active_team.flag_icon();
01165     std::string old_rgb = game_config::flag_rgb;
01166     std::string new_rgb = team::get_side_color_index(resources::screen->playing_side());
01167     std::string mods = "~RC(" + old_rgb + ">" + new_rgb + ")";
01168     if (flag_icon.empty())
01169         flag_icon = game_config::images::flag_icon;
01170     return image_report(flag_icon + mods, active_team.current_player());
01171 }
01172 
01173 REPORT_GENERATOR(observers)
01174 {
01175     const std::set<std::string> &observers = resources::screen->observers();
01176     if (observers.empty())
01177         return report();
01178 
01179     std::ostringstream str;
01180     str << _("Observers:") << '\n';
01181     foreach (const std::string &obs, observers) {
01182         str << obs << '\n';
01183     }
01184     return image_report(game_config::images::observer, str.str());
01185 }
01186 
01187 /* TODO unused
01188 REPORT_GENERATOR(selected_terrain)
01189 {
01190     const std::string selected_terrain = editor::get_selected_terrain();
01191     if (selected_terrain.empty())
01192         return report();
01193     else
01194         return text_report(selected_terrain);
01195 }
01196 */
01197 
01198 /* TODO this is unused
01199 REPORT_GENERATOR(edit_left_button_function)
01200 {
01201     const std::string left_button_function = editor::get_left_button_function();
01202     if (left_button_function.empty())
01203         return report();
01204     else
01205         return text_report(left_button_function);
01206 }
01207 */
01208 
01209 REPORT_GENERATOR(editor_tool_hint)
01210 {
01211     return report();
01212 }
01213 
01214 REPORT_GENERATOR(report_clock)
01215 {
01216     time_t t = std::time(NULL);
01217     struct tm *lt = std::localtime(&t);
01218     if (!lt) return report();
01219     char temp[15];
01220     size_t s = std::strftime(temp, 15,
01221         (preferences::use_twelve_hour_clock_format() ? _("%I:%M %p") : _("%H:%M")),
01222         lt);
01223     return s ? text_report(temp) : report();
01224 
01225 }
01226 
01227 REPORT_GENERATOR(report_countdown)
01228 {
01229     int viewing_side = resources::screen->viewing_side();
01230     const team &viewing_team = (*resources::teams)[viewing_side - 1];
01231     int min, sec;
01232     if (viewing_team.countdown_time() == 0)
01233         return report_report_clock();
01234     std::ostringstream str;
01235     sec = viewing_team.countdown_time() / 1000;
01236     char const *end = naps;
01237     if (viewing_side != resources::screen->playing_side())
01238         str << span_color(font::GRAY_COLOR);
01239     else if (sec < 60)
01240         str << "<span foreground=\"#c80000\">";
01241     else if (sec < 120)
01242         str << "<span foreground=\"#c8c800\">";
01243     else
01244         end = "";
01245     min = sec / 60;
01246     str << min << ':';
01247     sec = sec % 60;
01248     if (sec < 10) str << '0';
01249     str << sec << end;
01250     return text_report(str.str());
01251 }
01252 
01253 static std::set<std::string> all_reports;
01254 
01255 void reports::reset_generators()
01256 {
01257     foreach (dynamic_report_generators::value_type &rg, dynamic_generators) {
01258         delete rg.second;
01259     }
01260     dynamic_generators.clear();
01261     all_reports.clear();
01262 }
01263 
01264 void reports::register_generator(const std::string &name, reports::generator *g)
01265 {
01266     std::pair<dynamic_report_generators::iterator, bool> ib =
01267         dynamic_generators.insert(std::make_pair(name, g));
01268     if (!ib.second) {
01269         delete ib.first->second;
01270         ib.first->second = g;
01271     }
01272 }
01273 
01274 config reports::generate_report(const std::string &name, bool only_static)
01275 {
01276     if (!only_static) {
01277         dynamic_report_generators::const_iterator i = dynamic_generators.find(name);
01278         if (i != dynamic_generators.end())
01279             return i->second->generate();
01280     }
01281     static_report_generators::const_iterator j = static_generators.find(name);
01282     if (j != static_generators.end())
01283         return j->second();
01284     return report();
01285 }
01286 
01287 const std::set<std::string> &reports::report_list()
01288 {
01289     if (!all_reports.empty()) return all_reports;
01290     foreach (const static_report_generators::value_type &v, static_generators) {
01291         all_reports.insert(v.first);
01292     }
01293     foreach (const dynamic_report_generators::value_type &v, dynamic_generators) {
01294         all_reports.insert(v.first);
01295     }
01296     return all_reports;
01297 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:08 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs