The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
statistics.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[email protected]>
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 /**
16  * @file
17  * Manage statistics: recruitments, recalls, kills, losses, etc.
18  */
19 
20 #include "global.hpp"
21 #include "statistics.hpp"
22 #include "log.hpp"
23 #include "resources.hpp" // Needed for teams, to get team save_id for a unit
25 #include "team.hpp" // Needed to get team save_id
26 #include "units/unit.hpp"
27 #include "util.hpp"
28 
29 static lg::log_domain log_engine("engine");
30 #define DBG_NG LOG_STREAM(debug, log_engine)
31 #define ERR_NG LOG_STREAM(err, log_engine)
32 
33 namespace {
34 
35 // This variable is true whenever the statistics are mid-scenario.
36 // This means a new scenario shouldn't be added to the master stats record.
37 bool mid_scenario = false;
38 
39 typedef statistics::stats stats;
40 typedef std::map<std::string,stats> team_stats_t;
41 
42 std::string get_team_save_id(const unit & u)
43 {
44  assert(resources::teams);
45  return resources::teams->at(u.side()-1).save_id();
46 }
47 
48 struct scenario_stats
49 {
50  explicit scenario_stats(const std::string& name) :
51  team_stats(),
52  scenario_name(name)
53  {}
54 
55  explicit scenario_stats(const config& cfg);
56 
57  config write() const;
58  void write(config_writer &out) const;
59 
60  team_stats_t team_stats;
61  std::string scenario_name;
62 };
63 
64 scenario_stats::scenario_stats(const config& cfg) :
65  team_stats(),
66  scenario_name(cfg["scenario"])
67 {
68  for(const config &team : cfg.child_range("team")) {
69  team_stats[team["save_id"]] = stats(team);
70  }
71 }
72 
74 {
75  config res;
76  res["scenario"] = scenario_name;
77  for(team_stats_t::const_iterator i = team_stats.begin(); i != team_stats.end(); ++i) {
78  res.add_child("team",i->second.write());
79  }
80 
81  return res;
82 }
83 
84 void scenario_stats::write(config_writer &out) const
85 {
86  out.write_key_val("scenario", scenario_name);
87  for(team_stats_t::const_iterator i = team_stats.begin(); i != team_stats.end(); ++i) {
88  out.open_child("team");
89  i->second.write(out);
90  out.close_child("team");
91  }
92 }
93 
94 std::vector<scenario_stats> master_stats;
95 
96 } // end anon namespace
97 
98 static stats &get_stats(const std::string &save_id)
99 {
100  if(master_stats.empty()) {
101  master_stats.push_back(scenario_stats(std::string()));
102  }
103 
104  team_stats_t& team_stats = master_stats.back().team_stats;
105  return team_stats[save_id];
106 }
107 
108 static config write_str_int_map(const stats::str_int_map& m)
109 {
110  config res;
111  for(stats::str_int_map::const_iterator i = m.begin(); i != m.end(); ++i) {
112  res[i->first] = i->second;
113  }
114 
115  return res;
116 }
117 
118 static void write_str_int_map(config_writer &out, const stats::str_int_map& m)
119 {
120  for(stats::str_int_map::const_iterator i = m.begin(); i != m.end(); ++i) {
121  out.write_key_val(i->first, i->second);
122  }
123 }
124 
125 static stats::str_int_map read_str_int_map(const config& cfg)
126 {
127  stats::str_int_map m;
128  for(const config::attribute &i : cfg.attribute_range()) {
129  m[i.first] = i.second;
130  }
131 
132  return m;
133 }
134 
135 static config write_battle_result_map(const stats::battle_result_map& m)
136 {
137  config res;
138  for(stats::battle_result_map::const_iterator i = m.begin(); i != m.end(); ++i) {
139  config& new_cfg = res.add_child("sequence");
140  new_cfg = write_str_int_map(i->second);
141  new_cfg["_num"] = i->first;
142  }
143 
144  return res;
145 }
146 
147 static void write_battle_result_map(config_writer &out, const stats::battle_result_map& m)
148 {
149  for(stats::battle_result_map::const_iterator i = m.begin(); i != m.end(); ++i) {
150  out.open_child("sequence");
151  write_str_int_map(out, i->second);
152  out.write_key_val("_num", i->first);
153  out.close_child("sequence");
154  }
155 }
156 
157 static stats::battle_result_map read_battle_result_map(const config& cfg)
158 {
159  stats::battle_result_map m;
160  for(const config &i : cfg.child_range("sequence"))
161  {
162  config item = i;
163  int key = item["_num"];
164  item.remove_attribute("_num");
165  m[key] = read_str_int_map(item);
166  }
167 
168  return m;
169 }
170 
171 static void merge_str_int_map(stats::str_int_map& a, const stats::str_int_map& b)
172 {
173  for(stats::str_int_map::const_iterator i = b.begin(); i != b.end(); ++i) {
174  a[i->first] += i->second;
175  }
176 }
177 
178 static void merge_battle_result_maps(stats::battle_result_map& a, const stats::battle_result_map& b)
179 {
180  for(stats::battle_result_map::const_iterator i = b.begin(); i != b.end(); ++i) {
181  merge_str_int_map(a[i->first],i->second);
182  }
183 }
184 
185 static void merge_stats(stats& a, const stats& b)
186 {
187  DBG_NG << "Merging statistics\n";
188  merge_str_int_map(a.recruits,b.recruits);
189  merge_str_int_map(a.recalls,b.recalls);
190  merge_str_int_map(a.advanced_to,b.advanced_to);
191  merge_str_int_map(a.deaths,b.deaths);
192  merge_str_int_map(a.killed,b.killed);
193 
194  merge_battle_result_maps(a.attacks,b.attacks);
195  merge_battle_result_maps(a.defends,b.defends);
196 
197  a.recruit_cost += b.recruit_cost;
198  a.recall_cost += b.recall_cost;
199 
200  a.damage_inflicted += b.damage_inflicted;
201  a.damage_taken += b.damage_taken;
202  a.expected_damage_inflicted += b.expected_damage_inflicted;
203  a.expected_damage_taken += b.expected_damage_taken;
204  // Only take the last value for this turn
205  a.turn_damage_inflicted = b.turn_damage_inflicted;
206  a.turn_damage_taken = b.turn_damage_taken;
207  a.turn_expected_damage_inflicted = b.turn_expected_damage_inflicted;
208  a.turn_expected_damage_taken = b.turn_expected_damage_taken;
209 }
210 
211 namespace statistics
212 {
213 
215  recruits(),
216  recalls(),
217  advanced_to(),
218  deaths(),
219  killed(),
220  recruit_cost(0),
221  recall_cost(0),
222  attacks(),
223  defends(),
224  damage_inflicted(0),
225  damage_taken(0),
226  turn_damage_inflicted(0),
227  turn_damage_taken(0),
228  expected_damage_inflicted(0),
229  expected_damage_taken(0),
230  turn_expected_damage_inflicted(0),
231  turn_expected_damage_taken(0),
232  save_id()
233 {}
234 
235 stats::stats(const config& cfg) :
236  recruits(),
237  recalls(),
238  advanced_to(),
239  deaths(),
240  killed(),
241  recruit_cost(0),
242  recall_cost(0),
243  attacks(),
244  defends(),
245  damage_inflicted(0),
246  damage_taken(0),
247  turn_damage_inflicted(0),
248  turn_damage_taken(0),
249  expected_damage_inflicted(0),
250  expected_damage_taken(0),
251  turn_expected_damage_inflicted(0),
252  turn_expected_damage_taken(0),
253  save_id()
254 {
255  read(cfg);
256 }
257 
259 {
260  config res;
261  res.add_child("recruits",write_str_int_map(recruits));
262  res.add_child("recalls",write_str_int_map(recalls));
263  res.add_child("advances",write_str_int_map(advanced_to));
264  res.add_child("deaths",write_str_int_map(deaths));
265  res.add_child("killed",write_str_int_map(killed));
266  res.add_child("attacks",write_battle_result_map(attacks));
267  res.add_child("defends",write_battle_result_map(defends));
268 
269  res["recruit_cost"] = recruit_cost;
270  res["recall_cost"] = recall_cost;
271 
272  res["damage_inflicted"] = damage_inflicted;
273  res["damage_taken"] = damage_taken;
274  res["expected_damage_inflicted"] = expected_damage_inflicted;
275  res["expected_damage_taken"] = expected_damage_taken;
276 
277  res["turn_damage_inflicted"] = turn_damage_inflicted;
278  res["turn_damage_taken"] = turn_damage_taken;
279  res["turn_expected_damage_inflicted"] = turn_expected_damage_inflicted;
280  res["turn_expected_damage_taken"] = turn_expected_damage_taken;
281 
282  res["save_id"] = save_id;
283 
284  return res;
285 }
286 
287 void stats::write(config_writer &out) const
288 {
289  out.open_child("recruits");
291  out.close_child("recruits");
292  out.open_child("recalls");
294  out.close_child("recalls");
295  out.open_child("advances");
297  out.close_child("advances");
298  out.open_child("deaths");
300  out.close_child("deaths");
301  out.open_child("killed");
303  out.close_child("killed");
304  out.open_child("attacks");
306  out.close_child("attacks");
307  out.open_child("defends");
309  out.close_child("defends");
310 
311  out.write_key_val("recruit_cost", recruit_cost);
312  out.write_key_val("recall_cost", recall_cost);
313 
314  out.write_key_val("damage_inflicted", damage_inflicted);
315  out.write_key_val("damage_taken", damage_taken);
316  out.write_key_val("expected_damage_inflicted", expected_damage_inflicted);
317  out.write_key_val("expected_damage_taken", expected_damage_taken);
318 
319  out.write_key_val("turn_damage_inflicted", turn_damage_inflicted);
320  out.write_key_val("turn_damage_taken", turn_damage_taken);
321  out.write_key_val("turn_expected_damage_inflicted", turn_expected_damage_inflicted);
322  out.write_key_val("turn_expected_damage_taken", turn_expected_damage_taken);
323 
324  out.write_key_val("save_id", save_id);
325 }
326 
327 void stats::read(const config& cfg)
328 {
329  if (const config &c = cfg.child("recruits")) {
331  }
332  if (const config &c = cfg.child("recalls")) {
334  }
335  if (const config &c = cfg.child("advances")) {
337  }
338  if (const config &c = cfg.child("deaths")) {
340  }
341  if (const config &c = cfg.child("killed")) {
343  }
344  if (const config &c = cfg.child("recalls")) {
346  }
347  if (const config &c = cfg.child("attacks")) {
349  }
350  if (const config &c = cfg.child("defends")) {
352  }
353 
354  recruit_cost = cfg["recruit_cost"].to_int();
355  recall_cost = cfg["recall_cost"].to_int();
356 
357  damage_inflicted = cfg["damage_inflicted"].to_long_long();
358  damage_taken = cfg["damage_taken"].to_long_long();
359  expected_damage_inflicted = cfg["expected_damage_inflicted"].to_long_long();
360  expected_damage_taken = cfg["expected_damage_taken"].to_long_long();
361 
362  turn_damage_inflicted = cfg["turn_damage_inflicted"].to_long_long();
363  turn_damage_taken = cfg["turn_damage_taken"].to_long_long();
364  turn_expected_damage_inflicted = cfg["turn_expected_damage_inflicted"].to_long_long();
365  turn_expected_damage_taken = cfg["turn_expected_damage_taken"].to_long_long();
366 
367  save_id = cfg["save_id"].str();
368 }
369 
371 {
372  if(!mid_scenario || master_stats.empty()) {
373  master_stats.push_back(scenario_stats(name));
374  }
375 
376  mid_scenario = true;
377 }
378 
380 {
381  mid_scenario = false;
382 }
383 
385  const unit& d, int a_cth, int d_cth) :
386  attacker_type(a.type_id()),
387  defender_type(d.type_id()),
388  attacker_side(get_team_save_id(a)),
389  defender_side(get_team_save_id(d)),
390  chance_to_hit_defender(a_cth),
391  chance_to_hit_attacker(d_cth),
392  attacker_res(),
393  defender_res()
394 {
395 }
396 
398 {
399  std::string attacker_key = "s" + attacker_res;
400  std::string defender_key = "s" + defender_res;
401 
402  attacker_stats().attacks[chance_to_hit_defender][attacker_key]++;
403  defender_stats().defends[chance_to_hit_attacker][defender_key]++;
404 }
405 
407 {
408  return get_stats(attacker_side);
409 }
410 
412 {
413  return get_stats(defender_side);
414 }
415 
416 void attack_context::attack_expected_damage(double attacker_inflict_, double defender_inflict_)
417 {
418  int attacker_inflict = round_double(attacker_inflict_ * stats::decimal_shift);
419  int defender_inflict = round_double(defender_inflict_ * stats::decimal_shift);
420  stats &att_stats = attacker_stats(), &def_stats = defender_stats();
421  att_stats.expected_damage_inflicted += attacker_inflict;
422  att_stats.expected_damage_taken += defender_inflict;
423  def_stats.expected_damage_inflicted += defender_inflict;
424  def_stats.expected_damage_taken += attacker_inflict;
425  att_stats.turn_expected_damage_inflicted += attacker_inflict;
426  att_stats.turn_expected_damage_taken += defender_inflict;
427  def_stats.turn_expected_damage_inflicted += defender_inflict;
428  def_stats.turn_expected_damage_taken += attacker_inflict;
429 }
430 
431 
432 void attack_context::attack_result(hit_result res, int damage, int drain)
433 {
434  attacker_res.push_back(res == MISSES ? '0' : '1');
435  stats &att_stats = attacker_stats(), &def_stats = defender_stats();
436 
437  if(res != MISSES) {
438  // handle drain
439  att_stats.damage_taken -= drain;
440  def_stats.damage_inflicted -= drain;
441  att_stats.turn_damage_taken -= drain;
442  def_stats.turn_damage_inflicted -= drain;
443 
444  att_stats.damage_inflicted += damage;
445  def_stats.damage_taken += damage;
446  att_stats.turn_damage_inflicted += damage;
447  def_stats.turn_damage_taken += damage;
448  }
449 
450  if(res == KILLS) {
451  ++att_stats.killed[defender_type];
452  ++def_stats.deaths[defender_type];
453  }
454 }
455 
456 void attack_context::defend_result(hit_result res, int damage, int drain)
457 {
458  defender_res.push_back(res == MISSES ? '0' : '1');
459  stats &att_stats = attacker_stats(), &def_stats = defender_stats();
460 
461  if(res != MISSES) {
462  //handle drain
463  def_stats.damage_taken -= drain;
464  att_stats.damage_inflicted -= drain;
465  def_stats.turn_damage_taken -= drain;
466  att_stats.turn_damage_inflicted -= drain;
467 
468  att_stats.damage_taken += damage;
469  def_stats.damage_inflicted += damage;
470  att_stats.turn_damage_taken += damage;
471  def_stats.turn_damage_inflicted += damage;
472  }
473 
474  if(res == KILLS) {
475  ++att_stats.deaths[attacker_type];
476  ++def_stats.killed[attacker_type];
477  }
478 }
479 
480 void recruit_unit(const unit& u)
481 {
482  stats& s = get_stats(get_team_save_id(u));
483  s.recruits[u.type().base_id()]++;
484  s.recruit_cost += u.cost();
485 }
486 
487 void recall_unit(const unit& u)
488 {
489  stats& s = get_stats(get_team_save_id(u));
490  s.recalls[u.type_id()]++;
491  s.recall_cost += u.cost();
492 }
493 
494 void un_recall_unit(const unit& u)
495 {
496  stats& s = get_stats(get_team_save_id(u));
497  s.recalls[u.type_id()]--;
498  s.recall_cost -= u.cost();
499 }
500 
501 void un_recruit_unit(const unit& u)
502 {
503  stats& s = get_stats(get_team_save_id(u));
504  s.recruits[u.type().base_id()]--;
505  s.recruit_cost -= u.cost();
506 }
507 
508 int un_recall_unit_cost(const unit& u) // this really belongs elsewhere, perhaps in undo.cpp
509 { // but I'm too lazy to do it at the moment
510  stats& s = get_stats(get_team_save_id(u));
511  s.recalls[u.type_id()]--;
512  return u.recall_cost();
513 }
514 
515 
516 void advance_unit(const unit& u)
517 {
518  stats& s = get_stats(get_team_save_id(u));
519  s.advanced_to[u.type_id()]++;
520 }
521 
522 void reset_turn_stats(const std::string & save_id)
523 {
524  stats &s = get_stats(save_id);
525  s.turn_damage_inflicted = 0;
526  s.turn_damage_taken = 0;
529  s.save_id = save_id;
530 }
531 
533 {
534  stats res;
535 
536  DBG_NG << "calculate_stats, side: " << save_id << " master_stats.size: " << master_stats.size() << "\n";
537  // The order of this loop matters since the turn stats are taken from the
538  // last stats merged.
539  for ( size_t i = 0; i != master_stats.size(); ++i ) {
540  team_stats_t::const_iterator find_it = master_stats[i].team_stats.find(save_id);
541  if ( find_it != master_stats[i].team_stats.end() )
542  merge_stats(res, find_it->second);
543  }
544 
545  return res;
546 }
547 
548 
549 /**
550  * Returns a list of names and stats for each scenario in the current campaign.
551  * The front of the list is the oldest scenario; the back of the list is the
552  * (most) current scenario.
553  * Only scenarios with stats for the given @a side_id are included, but if no
554  * scenarios are applicable, then a vector containing a single dummy entry will
555  * be returned. (I.e., this never returns an empty vector.)
556  * This list is intended for the statistics dialog and may become invalid if
557  * new stats are recorded.
558  */
560 {
561  static const stats null_stats;
562  static const std::string null_name("");
563 
564  levels level_list;
565 
566  for ( size_t level = 0; level != master_stats.size(); ++level ) {
567  const team_stats_t & team_stats = master_stats[level].team_stats;
568 
569  team_stats_t::const_iterator find_it = team_stats.find(save_id);
570  if ( find_it != team_stats.end() )
571  level_list.push_back(make_pair(&master_stats[level].scenario_name,
572  &find_it->second));
573  }
574 
575  // Make sure we do return something (so other code does not have to deal
576  // with an empty list).
577  if ( level_list.empty() )
578  level_list.push_back(make_pair(&null_name, &null_stats));
579 
580  return level_list;
581 }
582 
583 
585 {
586  config res;
587  res["mid_scenario"] = mid_scenario;
588 
589  for(std::vector<scenario_stats>::const_iterator i = master_stats.begin(); i != master_stats.end(); ++i) {
590  res.add_child("scenario",i->write());
591  }
592 
593  return res;
594 }
595 
597 {
598  out.write_key_val("mid_scenario", mid_scenario ? "yes" : "no");
599 
600  for(std::vector<scenario_stats>::const_iterator i = master_stats.begin(); i != master_stats.end(); ++i) {
601  out.open_child("scenario");
602  i->write(out);
603  out.close_child("scenario");
604  }
605 }
606 
607 void read_stats(const config& cfg)
608 {
609  fresh_stats();
610  mid_scenario = cfg["mid_scenario"].to_bool();
611 
612  for(const config &s : cfg.child_range("scenario")) {
613  master_stats.push_back(scenario_stats(s));
614  }
615 }
616 
618 {
619  master_stats.clear();
620  mid_scenario = false;
621 }
622 
624 {
625  if(master_stats.empty() == false) {
626  master_stats.pop_back();
627  mid_scenario = false;
628  }
629 }
630 
632 {
633  int res = 0;
634  for(stats::str_int_map::const_iterator i = m.begin(); i != m.end(); ++i) {
635  res += i->second;
636  }
637 
638  return res;
639 }
640 
642 {
643  int cost = 0;
644  for (stats::str_int_map::const_iterator i = m.begin(); i != m.end(); ++i) {
645  const unit_type *t = unit_types.find(i->first);
646  if (!t) {
647  ERR_NG << "Statistics refer to unknown unit type '" << i->first << "'. Discarding." << std::endl;
648  } else {
649  cost += i->second * t->cost();
650  }
651  }
652 
653  return cost;
654 }
655 
656 } // end namespace statistics
657 
#define DBG_NG
Definition: statistics.cpp:30
child_itors child_range(const std::string &key)
Definition: config.cpp:613
void remove_attribute(const std::string &key)
Definition: config.cpp:534
static stats::battle_result_map read_battle_result_map(const config &cfg)
Definition: statistics.cpp:157
long long damage_inflicted
Definition: statistics.hpp:53
scenario_context(const std::string &name)
Definition: statistics.cpp:370
battle_result_map defends
Definition: statistics.hpp:51
Definition: unit.hpp:95
GLint level
Definition: glew.h:1220
const GLfloat * c
Definition: glew.h:12741
int sum_str_int_map(const stats::str_int_map &m)
Definition: statistics.cpp:631
void un_recall_unit(const unit &u)
Definition: statistics.cpp:494
attribute_map::value_type attribute
Definition: config.hpp:393
long long turn_damage_taken
Definition: statistics.hpp:54
void fresh_stats()
Definition: statistics.cpp:617
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
int side() const
Definition: unit.hpp:201
void defend_result(hit_result res, int damage, int drain)
Definition: statistics.cpp:456
#define d
-file sdl_utils.hpp
GLdouble GLdouble t
Definition: glew.h:1366
int round_double(double d)
Definition: util.hpp:67
void reset_turn_stats(const std::string &save_id)
Definition: statistics.cpp:522
str_int_map advanced_to
Definition: statistics.hpp:39
void recruit_unit(const unit &u)
Definition: statistics.cpp:480
std::vector< std::pair< const std::string *, const stats * > > levels
Stats (and name) for each scenario. The pointers are never nullptr.
Definition: statistics.hpp:115
long long expected_damage_taken
Definition: statistics.hpp:62
const unit_type & type() const
The type of the unit (accounting for gender and variation).
Definition: unit.hpp:144
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
long long turn_expected_damage_inflicted
Definition: statistics.hpp:63
const std::string & type_id() const
The id of the type of the unit.
Definition: unit.hpp:142
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
void write_key_val(const std::string &key, const T &value)
This template function will work with any type that can be assigned to an attribute_value.
static void merge_str_int_map(stats::str_int_map &a, const stats::str_int_map &b)
Definition: statistics.cpp:171
std::vector< team > * teams
Definition: resources.cpp:29
void close_child(const std::string &key)
static const int decimal_shift
Definition: statistics.hpp:56
Class for writing a config out to a file in pieces.
int un_recall_unit_cost(const unit &u)
Definition: statistics.cpp:508
void open_child(const std::string &key)
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
static stats & get_stats(const std::string &save_id)
Definition: statistics.cpp:98
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
static config write_battle_result_map(const stats::battle_result_map &m)
Definition: statistics.cpp:135
config & add_child(const std::string &key)
Definition: config.cpp:743
void read_stats(const config &cfg)
Definition: statistics.cpp:607
void read(const config &cfg)
Definition: statistics.cpp:327
str_int_map killed
Definition: statistics.hpp:39
Templates and utility-routines for strings and numbers.
int cost() const
Definition: types.hpp:134
void advance_unit(const unit &u)
Definition: statistics.cpp:516
GLuint res
Definition: glew.h:9258
config write() const
Definition: statistics.cpp:258
static lg::log_domain log_engine("engine")
str_int_map recruits
Definition: statistics.hpp:39
stats calculate_stats(const std::string &save_id)
Definition: statistics.cpp:532
str_int_map deaths
Definition: statistics.hpp:39
const_attr_itors attribute_range() const
Definition: config.cpp:984
long long damage_taken
Definition: statistics.hpp:53
size_t i
Definition: function.cpp:1057
static stats::str_int_map read_str_int_map(const config &cfg)
Definition: statistics.cpp:125
long long turn_damage_inflicted
Definition: statistics.hpp:54
static void merge_battle_result_maps(stats::battle_result_map &a, const stats::battle_result_map &b)
Definition: statistics.cpp:178
void recall_unit(const unit &u)
Definition: statistics.cpp:487
attack_context(const unit &a, const unit &d, int a_cth, int d_cth)
Definition: statistics.cpp:384
GLuint const GLchar * name
Definition: glew.h:1782
long long expected_damage_inflicted
Definition: statistics.hpp:62
const std::string & base_id() const
The id of the original type from which this (variation) descended.
Definition: types.hpp:119
const GLdouble * m
Definition: glew.h:6968
int recall_cost() const
Definition: unit.hpp:177
static void merge_stats(stats &a, const stats &b)
Definition: statistics.cpp:185
void attack_expected_damage(double attacker_inflict, double defender_inflict)
Definition: statistics.cpp:416
std::map< std::string, int > str_int_map
Definition: statistics.hpp:38
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:658
int cost() const
Definition: unit.hpp:284
config write_stats()
Definition: statistics.cpp:584
Standard logging facilities (interface).
void attack_result(hit_result res, int damage, int drain)
Definition: statistics.cpp:432
long long turn_expected_damage_taken
Definition: statistics.hpp:63
std::string save_id
Definition: statistics.hpp:64
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
battle_result_map attacks
Definition: statistics.hpp:51
void un_recruit_unit(const unit &u)
Definition: statistics.cpp:501
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
#define ERR_NG
Definition: statistics.cpp:31
void clear_current_scenario()
Definition: statistics.cpp:623
GLdouble s
Definition: glew.h:1358
static config write_str_int_map(const stats::str_int_map &m)
Definition: statistics.cpp:108
void write(std::ostream &out, configr_of const &cfg, unsigned int level)
Definition: parser.cpp:621
GLsizei const GLcharARB ** string
Definition: glew.h:4503