Convert cnames back to .h
[supertux.git] / src / statistics.cpp
1 //  $Id$
2 //
3 //  SuperTux (Statistics module)
4 //  Copyright (C) 2004 Ricardo Cruz <rick2@aeiou.pt>
5 //  Copyright (C) 2006 Ondrej Hosek <ondra.hosek@gmail.com>
6 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU General Public License
10 //  as published by the Free Software Foundation; either version 2
11 //  of the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include <config.h>
22
23 #include <assert.h>
24 #include <math.h>
25 #include <sstream>
26 #include <limits>
27 #include "video/drawing_context.hpp"
28 #include "gettext.hpp"
29 #include "lisp/writer.hpp"
30 #include "lisp/lisp.hpp"
31 #include "resources.hpp"
32 #include "main.hpp"
33 #include "statistics.hpp"
34 #include "log.hpp"
35
36 namespace {
37   const int nv_coins = std::numeric_limits<int>::min();
38   const int nv_badguys = std::numeric_limits<int>::min();
39   const float nv_time = std::numeric_limits<float>::max();
40   const int nv_secrets = std::numeric_limits<int>::min();
41 }
42
43 float WMAP_INFO_LEFT_X;
44 float WMAP_INFO_RIGHT_X;
45 float WMAP_INFO_TOP_Y1;
46 float WMAP_INFO_TOP_Y2;
47
48 Statistics::Statistics() : coins(nv_coins), total_coins(nv_coins), badguys(nv_badguys), total_badguys(nv_badguys), time(nv_time), secrets(nv_secrets), total_secrets(nv_secrets), valid(true), display_stat(0)
49 {
50   WMAP_INFO_LEFT_X = (SCREEN_WIDTH/2 + 80) + 32;
51   WMAP_INFO_RIGHT_X = SCREEN_WIDTH/2 + 368;
52   WMAP_INFO_TOP_Y1 = SCREEN_HEIGHT/2 + 172 - 16;
53   WMAP_INFO_TOP_Y2 = SCREEN_HEIGHT/2 + 172;
54 }
55
56 Statistics::~Statistics()
57 {
58 }
59
60 void
61 Statistics::parse(const lisp::Lisp& reader)
62 {
63   reader.get("coins-collected", coins);
64   reader.get("coins-collected-total", total_coins);
65   reader.get("badguys-killed", badguys);
66   reader.get("badguys-killed-total", total_badguys);
67   reader.get("time-needed", time);
68   reader.get("secrets-found", secrets);
69   reader.get("secrets-found-total", total_secrets);
70 }
71
72 void
73 Statistics::write(lisp::Writer& writer)
74 {
75   writer.write_int("coins-collected", coins);
76   writer.write_int("coins-collected-total", total_coins);
77   writer.write_int("badguys-killed", badguys);
78   writer.write_int("badguys-killed-total", total_badguys);
79   writer.write_float("time-needed", time);
80   writer.write_int("secrets-found", secrets);
81   writer.write_int("secrets-found-total", total_secrets);
82 }
83
84 //define TOTAL_DISPLAY_TIME  3400
85 //define FADING_TIME          600
86
87 #define TOTAL_DISPLAY_TIME  5
88 #define FADING_TIME         1
89
90 void
91 Statistics::draw_worldmap_info(DrawingContext& context)
92 {
93   // skip draw if level was never played
94   if (coins == nv_coins) return;
95
96   // skip draw if stats were declared invalid
97   if (!valid) return;
98
99   context.draw_text(white_small_text, std::string("- ") + _("Best Level Statistics") + " -", Vector((WMAP_INFO_LEFT_X + WMAP_INFO_RIGHT_X) / 2, WMAP_INFO_TOP_Y1), ALIGN_CENTER, LAYER_GUI);
100
101   float alpha;
102   if(timer.get_timegone() < FADING_TIME)
103     alpha = (timer.get_timegone() * 1.0f / FADING_TIME);
104   else if(timer.get_timeleft() < FADING_TIME)
105     alpha = (timer.get_timeleft() * 1.0f / FADING_TIME);
106   else
107     alpha = 1.0f;
108
109   context.push_transform();
110   context.set_alpha(alpha);
111
112   char caption_buf[128];
113   char stat_buf[128];
114   switch (display_stat)
115   {
116     case 0:
117       snprintf(caption_buf, sizeof(caption_buf), _("Max coins collected:"));
118       snprintf(stat_buf, sizeof(stat_buf), "%d/%d", coins, total_coins);
119       break;
120     case 1:
121       snprintf(caption_buf, sizeof(caption_buf), _("Max fragging:"));
122       snprintf(stat_buf, sizeof(stat_buf), "%d/%d", badguys, total_badguys);
123       break;
124     case 2:
125       snprintf(caption_buf, sizeof(caption_buf), _("Min time needed:"));
126       {
127         int csecs = (int)(time * 100);
128         int mins = (int)(csecs / 6000);
129         int secs = (csecs % 6000) / 100;
130         snprintf(stat_buf, sizeof(stat_buf), "%02d:%02d", mins,secs);
131       }
132       break;
133     case 3:
134       snprintf(caption_buf, sizeof(caption_buf), _("Max secrets found:"));
135       snprintf(stat_buf, sizeof(stat_buf), "%d/%d", secrets, total_secrets);
136       break;
137     default:
138       log_debug << "Invalid stat requested to be drawn" << std::endl;
139       break;
140   }
141
142   if (!timer.started())
143   {
144     timer.start(TOTAL_DISPLAY_TIME);
145     display_stat++;
146     if (display_stat > 3) display_stat = 0;
147   }
148
149   context.draw_text(white_small_text, caption_buf, Vector(WMAP_INFO_LEFT_X, WMAP_INFO_TOP_Y2), ALIGN_LEFT, LAYER_GUI);
150   context.draw_text(white_small_text, stat_buf, Vector(WMAP_INFO_RIGHT_X, WMAP_INFO_TOP_Y2), ALIGN_RIGHT, LAYER_GUI);
151   context.pop_transform();
152 }
153
154 void
155 Statistics::draw_message_info(DrawingContext& context, std::string title)
156 {
157   // skip draw if level was never played
158   // TODO: do we need this?
159   if (coins == nv_coins) return;
160
161   // skip draw if stats were declared invalid
162   if (!valid) return;
163
164   const float width = white_small_text->get_text_width("Max coins collected: 1111 / 1111");
165   const float left = (SCREEN_WIDTH - width) / 2;
166   const float right = (SCREEN_WIDTH + width) / 2;
167
168   context.draw_text(gold_text, title, Vector(SCREEN_WIDTH/2, 410), ALIGN_CENTER, LAYER_GUI);
169
170   char stat_buf[128];
171   int py = 450 + 18;
172
173   snprintf(stat_buf, sizeof(stat_buf), "%d/%d", coins, total_coins);
174   context.draw_text(white_small_text, _("Max coins collected:"), Vector(left, py), ALIGN_LEFT, LAYER_GUI);
175   context.draw_text(white_small_text, "%d / %d", Vector(right, py), ALIGN_RIGHT, LAYER_GUI);
176   py+=18;
177
178   snprintf(stat_buf, sizeof(stat_buf), "%d/%d", badguys, total_badguys);
179   context.draw_text(white_small_text, _("Max fragging:"), Vector(left, py), ALIGN_LEFT, LAYER_GUI);
180   context.draw_text(white_small_text, "%d / %d", Vector(right, py), ALIGN_RIGHT, LAYER_GUI);
181   py+=18;
182
183   int csecs = (int)(time * 100);
184   int mins = (int)(csecs / 6000);
185   int secs = (csecs % 6000) / 100;
186   snprintf(stat_buf, sizeof(stat_buf), "%02d:%02d", mins,secs);
187   context.draw_text(white_small_text, _("Min time needed:"), Vector(left, py), ALIGN_LEFT, LAYER_GUI);
188   context.draw_text(white_small_text, "%02d:%02d", Vector(right, py), ALIGN_RIGHT, LAYER_GUI);
189   py+=18;
190
191   snprintf(stat_buf, sizeof(stat_buf), "%d/%d", secrets, total_secrets);
192   context.draw_text(white_small_text, _("Max secrets found:"), Vector(left, py), ALIGN_LEFT, LAYER_GUI);
193   context.draw_text(white_small_text, "%d / %d", Vector(right, py), ALIGN_RIGHT, LAYER_GUI);
194   py+=18;
195 }
196
197 void
198 Statistics::draw_endseq_panel(DrawingContext& context, Statistics* best_stats, Surface* backdrop)
199 {
200   // skip draw if level was never played
201   // TODO: do we need this?
202   if (coins == nv_coins) return;
203
204   // skip draw if stats were declared invalid
205   if (!valid) return;
206
207   // abort if we have no backdrop
208   if (!backdrop) return;
209
210   int box_w = 220+110+110;
211   int box_h = 30+20+20+20;
212   int box_x = (int)((SCREEN_WIDTH - box_w) / 2);
213   int box_y = (int)(SCREEN_HEIGHT / 2) - box_h;
214
215   int bd_w = (int)backdrop->get_width();
216   int bd_h = (int)backdrop->get_height();
217   int bd_x = (int)((SCREEN_WIDTH - bd_w) / 2);
218   int bd_y = box_y + (box_h / 2) - (bd_h / 2);
219
220   int col1_x = box_x;
221   int col2_x = col1_x+200;
222   int col3_x = col2_x+130;
223
224   int row1_y = box_y;
225   int row2_y = row1_y+30;
226   int row3_y = row2_y+20;
227   int row4_y = row3_y+20;
228
229   context.push_transform();
230   context.set_alpha(0.5);
231   context.draw_surface(backdrop, Vector(bd_x, bd_y), LAYER_GUI);
232   context.pop_transform();
233
234   char buf[129];
235   context.draw_text(white_text, _("You"), Vector(col2_x, row1_y), ALIGN_LEFT, LAYER_GUI);
236   context.draw_text(white_text, _("Best"), Vector(col3_x, row1_y), ALIGN_LEFT, LAYER_GUI);
237
238   context.draw_text(white_text, _("Coins"), Vector(col2_x-16, row2_y), ALIGN_RIGHT, LAYER_GUI);
239   snprintf(buf, sizeof(buf), "%d/%d", std::min(coins, 999), std::min(total_coins, 999));
240   context.draw_text(gold_text, buf, Vector(col2_x, row2_y), ALIGN_LEFT, LAYER_GUI);
241   if (best_stats && (best_stats->coins > coins)) {
242     snprintf(buf, sizeof(buf), "%d/%d", std::min(best_stats->coins, 999), std::min(best_stats->total_coins, 999));
243   }
244   context.draw_text(gold_text, buf, Vector(col3_x, row2_y), ALIGN_LEFT, LAYER_GUI);
245
246   context.draw_text(white_text, _("Secrets"), Vector(col2_x-16, row4_y), ALIGN_RIGHT, LAYER_GUI);
247   snprintf(buf, sizeof(buf), "%d/%d", secrets, total_secrets);
248   context.draw_text(gold_text, buf, Vector(col2_x, row4_y), ALIGN_LEFT, LAYER_GUI);
249   if (best_stats && (best_stats->secrets > secrets)) {
250     snprintf(buf, sizeof(buf), "%d/%d", best_stats->secrets, best_stats->total_secrets);
251   }
252   context.draw_text(gold_text, buf, Vector(col3_x, row4_y), ALIGN_LEFT, LAYER_GUI);
253
254   context.draw_text(white_text, _("Time"), Vector(col2_x-16, row3_y), ALIGN_RIGHT, LAYER_GUI);
255   int csecs = (int)(time * 100);
256   int mins = (int)(csecs / 6000);
257   int secs = (csecs % 6000) / 100;
258   snprintf(buf, sizeof(buf), "%02d:%02d", mins,secs);
259   context.draw_text(gold_text, buf, Vector(col2_x, row3_y), ALIGN_LEFT, LAYER_GUI);
260   if (best_stats && (best_stats->time < time)) {
261     int csecs = (int)(best_stats->time * 100);
262     int mins = (int)(csecs / 6000);
263     int secs = (csecs % 6000) / 100;
264     snprintf(buf, sizeof(buf), "%02d:%02d", mins,secs);
265   }
266   context.draw_text(gold_text, buf, Vector(col3_x, row3_y), ALIGN_LEFT, LAYER_GUI);
267 }
268
269 void
270 Statistics::reset()
271 {
272   coins = 0;
273   badguys = 0;
274   time = 0;
275   secrets = 0;
276 }
277
278 void
279 Statistics::merge(Statistics& s2)
280 {
281   if (!s2.valid) return;
282   coins = std::max(coins, s2.coins);
283   total_coins = s2.total_coins;
284   badguys = std::max(badguys, s2.badguys);
285   total_badguys = s2.total_badguys;
286   time = std::min(time, s2.time);
287   secrets = std::max(secrets, s2.secrets);
288   total_secrets = s2.total_secrets;
289 }
290
291 void
292 Statistics::operator+=(const Statistics& s2)
293 {
294   if (!s2.valid) return;
295   if (s2.coins != nv_coins) coins += s2.coins;
296   if (s2.total_coins != nv_coins) total_coins += s2.total_coins;
297   if (s2.badguys != nv_badguys) badguys += s2.badguys;
298   if (s2.total_badguys != nv_badguys) total_badguys += s2.total_badguys;
299   if (s2.time != nv_time) time += s2.time;
300   if (s2.secrets != nv_secrets) secrets += s2.secrets;
301   if (s2.total_secrets != nv_secrets) total_secrets += s2.total_secrets;
302 }
303
304 void
305 Statistics::declare_invalid()
306 {
307   valid = false;
308 }