The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
statistics_dialog.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2016 by Joerg Hinrichs <[email protected]>
3  wesnoth playturn Copyright (C) 2003 by David White <[email protected]>
4  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "gettext.hpp"
17 #include "marked-up_text.hpp"
18 #include "statistics_dialog.hpp"
19 #include "units/types.hpp"
20 #include "wml_separators.hpp"
21 #include "game_display.hpp"
22 
23 
25 // These values just need to be larger than the number of rows in the dialog.
26 static const int BUTTON_SCENE = 101;
27 static const int BUTTON_TOGGLE = 102;
28 
29 
30 namespace {
31 
32 #ifdef LOW_MEM
33 std::vector<std::string> create_unit_table(const statistics::stats::str_int_map& m, unsigned int /*team*/)
34 #else
35 std::vector<std::string> create_unit_table(const statistics::stats::str_int_map& m, unsigned int team)
36 #endif
37 {
38  std::vector<std::string> table;
39  for(statistics::stats::str_int_map::const_iterator i = m.begin(); i != m.end(); ++i) {
40  const unit_type *type = unit_types.find(i->first);
41  if (!type) continue;
42 
43  std::stringstream str;
44 
45  str << IMAGE_PREFIX << type->image();
46 #ifndef LOW_MEM
47  str << "~RC(" << type->flag_rgb() << ">" << team << ")";
48 #endif
49  str << COLUMN_SEPARATOR << type->type_name() << COLUMN_SEPARATOR << i->second << "\n";
50  table.push_back(str.str());
51  }
52 
53  return table;
54 }
55 
56 
57 void make_damage_line(std::vector<std::string>& items, const std::string& header,
58  const long long& damage, const long long& expected,
59  const long long& turn_damage, const long long& turn_expected,
60  bool show_this_turn)
61 {
63 
64  long long dsa = shift * damage - expected;
65  long long dst = shift * turn_damage - turn_expected;
66 
67  std::ostringstream str;
68  str << header << COLUMN_SEPARATOR
69  << damage << " / "
70  << (expected * 10 + shift / 2) / shift * 0.1
72  << ((dsa < 0) ^ (expected < 0) ? "" : "+")
73  << (expected == 0 ? 0 : 100 * dsa / expected) << '%';
74  if ( show_this_turn ) {
75  str << COLUMN_SEPARATOR
77  << turn_damage << " / "
78  << (turn_expected * 10 + shift / 2) / shift * 0.1
80  << ((dst < 0) ^ (turn_expected < 0) ? "" : "+")
81  << (turn_expected == 0 ? 0 : 100 * dst / turn_expected) << '%';
82  }
83  items.push_back(str.str());
84 }
85 
86 } //end anonymous namespace
87 
88 
89 /**
90  * Picks out the stats structure that was selected for displaying.
91  */
93 {
95 }
96 
97 
99 {
100  int sel = get_menu().selection();
101  bool has_details = sel < 5 && sel >= 0 && unit_count_[sel] > 0;
102  detail_btn_->enable(has_details);
103  if(dp_info.double_clicked && has_details) {
104  set_result(sel);
105  } else if(dp_info.new_key_down && !dp_info.key_down) {
107  }
108 
109  // Prepare the sub-dialog for Statistic Details
110  std::string title;
111  std::vector<std::string> items_sub;
112  switch(result()) {
113  case gui::CLOSE_DIALOG:
114  break;
115  case 0:
116  items_sub = create_unit_table(current_stats().recruits, team_num_);
117  title = _("Recruits");
118  break;
119  case 1:
120  items_sub = create_unit_table(current_stats().recalls, team_num_);
121  title = _("Recalls");
122  break;
123  case 2:
124  items_sub = create_unit_table(current_stats().advanced_to, team_num_);
125  title = _("Advancements");
126  break;
127  case 3:
128  items_sub = create_unit_table(current_stats().deaths, team_num_);
129  title = _("Losses");
130  break;
131  case 4:
132  // Give kills a (probably) different team color.
133  items_sub = create_unit_table(current_stats().killed, team_num_ == 1 ? 2 : 1);
134  title = _("Kills");
135  break;
136 
137  case BUTTON_SCENE:
138  // Scenario selection.
141  break;
142  case BUTTON_TOGGLE:
143  // Toggle between campaign and scenario stats.
146  break;
147 
148  default:
149  break;
150  }
151  if (items_sub.empty() == false) {
152  gui::dialog d(get_video(), title + " (" + player_name_ + ")", "", gui::CLOSE_ONLY);
153  d.set_menu(items_sub);
154  d.show();
155  dp_info.clear_buttons();
157  }
158 }
159 
160 
162  const std::string& title,
163  const unsigned int team,
164  const std::string& team_id,
165  const std::string& player) :
166  dialog(disp.video(), title, "", gui::NULL_DIALOG),
167  detail_btn_(new gui::standard_dialog_button(disp.video(), _("Details"), 0 , false)),
168  toggle_btn_(new gui::dialog_button(disp.video(), "", gui::button::TYPE_PRESS, BUTTON_TOGGLE)),
169  scene_btn_(new gui::dialog_button(disp.video(), _("Select Scenario"), gui::button::TYPE_PRESS, BUTTON_SCENE)),
170  player_name_(player),
171  campaign_(statistics::calculate_stats(team_id)),
172  scenarios_(statistics::level_stats(team_id)),
173  scenario_index_(scenarios_.size() - 1), // current scenario
174  team_num_(team),
175  unit_count_(5,0)
176 {
177  if ( scenarios_.size() > 1 ) {
180  }
182  add_button(new gui::standard_dialog_button(disp.video(), _("Close"), 1, true),
184 
185  // Initialize the displayed data.
186  if ( use_campaign_ || scenarios_.size() == 1 )
188  else {
189  // Starting with the scenario stats, but we need to make sure the
190  // window is wide enough for the campaign stats.
191  display_stats(true);
192  layout();
193  display_stats(false);
194  }
195 }
196 
197 
199 {
200 }
201 
202 
203 /**
204  * Fills in the text to be displayed in the dialog.
205  * This also updates the scenario/campaign toggle button.
206  *
207  * @param[in] campaign Indicates whether or not the campaign stats are to
208  * be displayed.
209  */
211 {
212  // Record which stats we will display.
213  use_campaign_ = campaign;
214  const statistics::stats & stats = current_stats();
215  const bool show_this_turn =
216  use_campaign_ || scenario_index_ + 1 == scenarios_.size();
217 
218  int n, cost;
219  std::vector<std::string> items;
220  // The heading for the menu items:
221  {
222  std::stringstream str;
223  str << HEADING_PREFIX
225  << font::BOLD_TEXT << (use_campaign_ ? _("Campaign") : _("Scenario"));
226  items.push_back(str.str());
227  }
228  // Prepare the menu items
229  {
230  std::stringstream str;
232  cost = stats.recruit_cost;
233  unit_count_[0] = n;
234  str << _("Recruits") << COLUMN_SEPARATOR << n
236  << COLUMN_SEPARATOR << IMAGE_PREFIX << "themes/gold.png"
237  << COLUMN_SEPARATOR << cost;
238  items.push_back(str.str());
239  }
240  {
241  std::stringstream str;
243  cost = stats.recall_cost;
244  unit_count_[1] = n;
245  str << _("Recalls") << COLUMN_SEPARATOR << n
247  << COLUMN_SEPARATOR << IMAGE_PREFIX << "themes/gold.png"
248  << COLUMN_SEPARATOR << cost;
249  items.push_back(str.str());
250  }
251  {
252  std::stringstream str;
254  unit_count_[2] = n;
255  str << _("Advancements") << COLUMN_SEPARATOR << n;
256  items.push_back(str.str());
257  }
258  {
259  std::stringstream str;
261  unit_count_[3] = n;
263  str << _("Losses") << COLUMN_SEPARATOR << n
265  << COLUMN_SEPARATOR << IMAGE_PREFIX << "themes/gold.png"
266  << COLUMN_SEPARATOR << cost;
267  items.push_back(str.str());
268  }
269  {
270  std::stringstream str;
272  unit_count_[4] = n;
274  str << _("Kills") << COLUMN_SEPARATOR << n
276  << COLUMN_SEPARATOR << IMAGE_PREFIX << "themes/gold.png"
277  << COLUMN_SEPARATOR << cost;
278  items.push_back(str.str());
279  }
280  items.push_back("");
281  {
282  std::stringstream str;
283  str << font::BOLD_TEXT << _("Damage")
284  << COLUMN_SEPARATOR << _("Overall");
285  if ( show_this_turn ) {
286  str << COLUMN_SEPARATOR
288  << COLUMN_SEPARATOR << _("This Turn");
289  }
290  items.push_back(str.str());
291  }
292 
293  make_damage_line(items, _("Inflicted"),
296  show_this_turn);
297  make_damage_line(items, _("Taken"),
298  stats.damage_taken, stats.expected_damage_taken,
300  show_this_turn);
301 
302  set_menu_items(items, true);
303  toggle_btn_->set_label(use_campaign_ ? _("Scenario") : _("Campaign"));
305 }
306 
307 
308 /**
309  * Implements the scenario selection popup.
310  */
312 {
313  // Prepare a list of scenario names.
314  std::vector<std::string> names;
315  for ( size_t i = 0; i != scenarios_.size(); ++i )
316  names.push_back(*scenarios_[i].first);
317 
318  // Let the player choose a scenario.
319  SDL_Rect const &loc = scene_btn_->location();
320  size_t new_scenario = gui::show_dialog(get_video(), nullptr, "", "",
321  gui::MESSAGE, &names, nullptr, "", nullptr,
322  -1, nullptr, loc.x, loc.y + loc.h);
323 
324  if ( new_scenario != scenario_index_ && new_scenario < scenarios_.size() )
325  {
326  // Switch the displayed data to the selected scenario.
327  scenario_index_ = new_scenario;
328  scene_btn_->set_label(*scenarios_[new_scenario].first);
329  display_stats(false);
330  }
331 }
332 
const statistics::stats & current_stats()
Picks out the stats structure that was selected for displaying.
long long damage_inflicted
Definition: statistics.hpp:53
void set_result(const int result)
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:112
void set_label(const std::string &val)
Definition: button.cpp:604
std::vector< int > unit_count_
int sum_str_int_map(const stats::str_int_map &m)
Definition: statistics.cpp:631
gui::dialog_button * toggle_btn_
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
static const int BUTTON_TOGGLE
virtual void enable(bool new_val=true)
Definition: button.cpp:386
void add_button(dialog_button *const btn, BUTTON_LOCATION loc)
General purpose widgets.
long long turn_damage_taken
Definition: statistics.hpp:54
const statistics::stats campaign_
void display_stats(bool campaign)
Fills in the text to be displayed in the dialog.
int sum_cost_str_int_map(const stats::str_int_map &m)
Definition: statistics.cpp:641
unit_type_data unit_types
Definition: types.cpp:1314
const std::string & image() const
Definition: types.hpp:138
const std::vector< std::string > items
#define d
int show(int xloc, int yloc)
str_int_map advanced_to
Definition: statistics.hpp:39
char const IMAGE_PREFIX
statistics_dialog(game_display &disp, const std::string &title, const unsigned int team, const std::string &team_id, const std::string &player)
long long expected_damage_taken
Definition: statistics.hpp:62
long long turn_expected_damage_inflicted
Definition: statistics.hpp:63
const statistics::levels scenarios_
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
gui::dialog_button * scene_btn_
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
const std::string & flag_rgb() const
Definition: types.hpp:147
static const int decimal_shift
Definition: statistics.hpp:56
GLenum GLenum dst
Definition: glew.h:2392
void set_menu(menu *const m)
void action(gui::dialog_process_info &dp_info)
levels level_stats(const std::string &save_id)
Returns a list of names and stats for each scenario in the current campaign.
Definition: statistics.cpp:559
str_int_map recalls
Definition: statistics.hpp:39
virtual dimension_measurements layout(int xloc=-1, int yloc=-1)
int show_dialog(CVideo &video, surface image, const std::string &caption, const std::string &message, DIALOG_TYPE type, const std::vector< std::string > *menu_items, const std::vector< preview_pane * > *preview_panes, const std::string &text_widget_label, std::string *text_widget_text, const int text_widget_max_chars, std::vector< check_item > *options, int xloc, int yloc, const dialog_frame::style *dialog_style, std::vector< dialog_button_info > *action_buttons, const menu::sorter *sorter, menu::style *menu_style)
void set_menu_items(const std::vector< std::string > &menu_items, bool keep_selection=false)
Changes (or sets, if not previously set) the dialog's menu items to the provided list.
str_int_map killed
Definition: statistics.hpp:39
GLuint const GLuint * names
Definition: glew.h:2552
str_int_map recruits
Definition: statistics.hpp:39
stats calculate_stats(const std::string &save_id)
Definition: statistics.cpp:532
int result() const
str_int_map deaths
Definition: statistics.hpp:39
CVideo & get_video()
long long damage_taken
Definition: statistics.hpp:53
size_t i
Definition: function.cpp:1057
long long turn_damage_inflicted
Definition: statistics.hpp:54
void do_scene_selection()
Implements the scenario selection popup.
long long expected_damage_inflicted
Definition: statistics.hpp:62
GLsizeiptr size
Definition: glew.h:1649
char const HEADING_PREFIX
GLclampd n
Definition: glew.h:5903
static const int BUTTON_SCENE
char const COLUMN_SEPARATOR
const GLdouble * m
Definition: glew.h:6968
std::map< std::string, int > str_int_map
Definition: statistics.hpp:38
gui::dialog_button * detail_btn_
CVideo & video()
Gets the underlying screen object.
Definition: display.hpp:202
GLint * first
Definition: glew.h:1496
long long turn_expected_damage_taken
Definition: statistics.hpp:63
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1155
const char BOLD_TEXT
SDL_Rect const & location() const
Definition: widget.cpp:144
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glew.h:3780
GLsizei const GLcharARB ** string
Definition: glew.h:4503
int selection() const
Definition: menu.cpp:369