1 /*
2 * Alizarin Tetris
3 * For the management of high scores.
4 *
5 * Copyright 2000, Kiri Wagstaff & Westley Weimer
6 */
7
8 #define BUFSIZE 256 /* 255 letters for each name */
9
10 #define NUM_HIGH_SCORES 10 /* number of scores to save */
11
12 #include <config.h>
13 #include <assert.h>
14 #include <ctype.h>
15
16 #include "atris.h"
17 #include "button.h"
18 #include "display.h"
19 #include "identity.h"
20 #include "grid.h"
21 #include "highscore.h"
22
23 #include "display.pro"
24 #include "identity.pro"
25
26 static char loaded = FALSE;
27 static int high_scores[NUM_HIGH_SCORES];
28 static char* high_names[NUM_HIGH_SCORES];
29 static char* high_dates[NUM_HIGH_SCORES];
30
31 static SDL_Rect hs, hs_border; /* where are the high scores? */
32 static int score_height; /* how high is each score? */
33
34 #define FIRST_SCORE_Y (hs.y + 60)
35
36 /***************************************************************************
37 * prep_hs_bg()
38 * Prepare the high score background.
39 ***************************************************************************/
40 static void
prep_hs_bg()41 prep_hs_bg()
42 {
43 hs.x = screen->w/20; hs.y = screen->h/20;
44 hs.w = 9*screen->w/10; hs.h = 18*screen->h/20;
45
46 draw_bordered_rect(&hs, &hs_border, 2);
47 }
48
49 /***************************************************************************
50 * save_high_scores()
51 * Save the high scores out to the disk.
52 ***************************************************************************/
53 static void
save_high_scores()54 save_high_scores()
55 {
56 FILE *fout;
57 int i;
58
59 if (!loaded)
60 return;
61
62 fout = fopen("Atris.Scores","wt");
63 if (!fout) {
64 Debug("Unable to write High Score file [Atris.Scores]: %s\n", strerror(errno));
65 return;
66 }
67
68 fprintf(fout,"# Alizarin Tetris High Score File\n");
69 for (i=0; i<NUM_HIGH_SCORES; i++)
70 fprintf(fout,"%04d|%s|%s\n",high_scores[i], high_dates[i], high_names[i]);
71 fclose(fout);
72 }
73
74
75 /***************************************************************************
76 * load_high_scores()
77 * Load the high scores from disk (and allocate space).
78 ***************************************************************************/
79 static void
load_high_scores()80 load_high_scores()
81 {
82 FILE* fin;
83 int i = 0;
84 char buf[2048];
85
86 if (!loaded) {
87 /* make up a dummy high score template first */
88
89 for (i=0; i<NUM_HIGH_SCORES; i++) {
90 high_names[i] = strdup("No one yet..."); Assert(high_names[i]);
91 high_dates[i] = strdup("Never"); Assert(high_dates[i]);
92 high_scores[i] = 0;
93 }
94 loaded = TRUE;
95 }
96
97 fin = fopen("Atris.Scores", "r");
98 if (fin) {
99
100 for (i=0; !feof(fin) && i < NUM_HIGH_SCORES; i++) {
101 char *p, *q;
102 /* read in a line of text, but skip comments and blanks */
103 do {
104 fgets(buf, sizeof(buf), fin);
105 } while (!feof(fin) && (buf[0] == '\n' || buf[0] == '#'));
106 /* are we done with this file? */
107 if (feof(fin)) break;
108 /* strip the newline */
109 if (strchr(buf,'\n'))
110 *(strchr(buf,'\n')) = 0;
111 /* format: "score|date|name" */
112
113 sscanf(buf,"%d",&high_scores[i]);
114 p = strchr(buf,'|');
115 if (!p) break;
116 p++;
117 q = strchr(p, '|');
118 if (!q) break;
119 Free(high_dates[i]); Free(high_names[i]);
120 *q = 0;
121 high_dates[i] = strdup(p); Assert(high_dates[i]);
122 q++;
123 high_names[i] = strdup(q); Assert(high_names[i]);
124 }
125 fclose(fin);
126 }
127 }
128
129 /***************************************************************************
130 * show_high_scores()
131 * Display the current high score list.
132 ***************************************************************************/
133 static void
show_high_scores()134 show_high_scores()
135 {
136 char buf[256];
137 int i, base;
138 int delta;
139
140 if (!loaded) load_high_scores();
141 prep_hs_bg();
142
143 draw_string("Alizarin Tetris High Scores", color_purple, screen->w/2,
144 hs.y, DRAW_LARGE | DRAW_UPDATE | DRAW_CENTER );
145
146 base = FIRST_SCORE_Y;
147
148 for (i=0; i<NUM_HIGH_SCORES; i++)
149 {
150 SPRINTF(buf, "%-2d)", i+1);
151 delta = draw_string(buf, color_blue, 3*screen->w/40, base, DRAW_UPDATE );
152
153 score_height = delta + 3;
154
155 SPRINTF(buf, "%-20s", high_names[i]);
156 draw_string(buf, color_red, 3*screen->w/20, base, DRAW_UPDATE );
157
158 SPRINTF(buf, "%.4d", high_scores[i]);
159 draw_string(buf, color_blue, 11*screen->w/20, base, DRAW_UPDATE );
160
161 SPRINTF(buf, "%s", high_dates[i]);
162 draw_string(buf, color_red, 7*screen->w/10, base, DRAW_UPDATE );
163
164 base += score_height;
165 }
166 }
167
168 /***************************************************************************
169 * is_high_score()
170 * Checks whether score qualifies as a high score.
171 * Returns 1 if so, 0 if not.
172 ***************************************************************************/
173 static int
is_high_score(int score)174 is_high_score(int score)
175 {
176 if (!loaded) load_high_scores();
177 return (score >= high_scores[NUM_HIGH_SCORES-1]);
178 }
179
180 /***************************************************************************
181 * update_high_scores()
182 * Modifies the high score list, adding in the current score and
183 * querying for a name.
184 ***************************************************************************/
185 static void
update_high_scores(int score)186 update_high_scores(int score)
187 {
188 unsigned int i, j;
189 char buf[256];
190 #if HAVE_STRFTIME
191 const struct tm* tm;
192 time_t t;
193 #endif
194
195 if (!is_high_score(score)) return;
196 if (!loaded) load_high_scores();
197
198 for (i=0; i<NUM_HIGH_SCORES; i++)
199 {
200 if (score >= high_scores[i])
201 {
202 prep_hs_bg();
203 /* move everything down */
204
205 Free(high_names[NUM_HIGH_SCORES-1]);
206 Free(high_dates[NUM_HIGH_SCORES-1]);
207
208 for (j=NUM_HIGH_SCORES-1; j>i; j--)
209 {
210 high_scores[j] = high_scores[j-1];
211 high_names[j] = high_names[j-1];
212 high_dates[j] = high_dates[j-1];
213 }
214 /* Get the date */
215 #if HAVE_STRFTIME
216 t = time(NULL); tm = localtime(&t);
217 strftime(buf, sizeof(buf), "%b %d %H:%M", tm);
218 high_dates[i] = strdup(buf);
219 #else
220 #warning "Since you do not have strftime(), you will not have accurate times in the high score list."
221 high_dates[i] = "Unknown Time";
222 #endif
223
224 high_scores[i] = score;
225 /* Display the high scores */
226 high_names[i] = " ";
227 show_high_scores();
228 /* get the new name */
229
230 draw_string("Enter your name!", color_purple, screen->w / 2, hs.y
231 + hs.h - 10, DRAW_CENTER | DRAW_ABOVE | DRAW_UPDATE);
232
233 high_names[i] = input_string(screen, 3*screen->w/20,
234 FIRST_SCORE_Y + score_height * i, 1);
235 break;
236 }
237 }
238 save_high_scores();
239 }
240
241 /***************************************************************************
242 * high_score_check()
243 * Checks for a high score; if so, updates the list. Displays list.
244 *********************************************************************PROTO*/
high_score_check(int level,int new_score)245 void high_score_check(int level, int new_score)
246 {
247 SDL_Event event;
248
249 clear_screen_to_flame();
250
251 if (level < 0) {
252 return;
253 }
254
255 /* Clear the queue */
256 while (SDL_PollEvent(&event)) {
257 poll_and_flame(&event);
258 }
259
260 /* Check for a new high score. If so, update the list. */
261 if (is_high_score(new_score)) {
262 update_high_scores(new_score);
263 show_high_scores();
264 } else {
265 char buf[BUFSIZE];
266
267 show_high_scores();
268 SPRINTF(buf,"Your score: %d", new_score);
269
270 draw_string(buf, color_purple, screen->w / 2, hs.y
271 + hs.h - 10, DRAW_CENTER | DRAW_ABOVE | DRAW_UPDATE);
272
273 }
274 /* wait for any key */
275 do {
276 poll_and_flame(&event);
277 } while (event.type != SDL_KEYDOWN);
278 }
279
280 /*
281 * $Log: highscore.c,v $
282 * Revision 1.31 2000/11/06 01:22:40 wkiri
283 * Updated menu system.
284 *
285 * Revision 1.30 2000/10/29 21:23:28 weimer
286 * One last round of header-file changes to reflect my newest and greatest
287 * knowledge of autoconf/automake. Now if you fail to have some bizarro
288 * function, we try to go on anyway unless it is vastly needed.
289 *
290 * Revision 1.29 2000/10/29 19:04:33 weimer
291 * minor highscore handling changes: new filename, use the draw_string() and
292 * draw_bordered_rect() and input_string() interfaces, handle the widget layer
293 * and the flame layer, etc. Also fix a minor bug where you would be prevented
294 * from settling if you pressed a key even if it didn't really move you. :-)
295 *
296 * Revision 1.28 2000/10/21 01:14:43 weimer
297 * massic autoconf/automake restructure ...
298 *
299 * Revision 1.27 2000/10/18 23:57:49 weimer
300 * general fixup, color changes, display changes.
301 * Notable: "Safe" Blits and Updates now perform "clipping". No more X errors,
302 * we hope!
303 *
304 * Revision 1.26 2000/09/09 17:05:35 wkiri
305 * Hideous log changes (Wes: how dare you include a comment character!)
306 *
307 * Revision 1.25 2000/09/09 16:58:27 weimer
308 * Sweeping Change of Ultimate Mastery. Main loop restructuring to clean up
309 * main(), isolate the behavior of the three game types. Move graphic files
310 * into graphics/-, style files into styles/-, remove some unused files,
311 * add game flow support (breaks between games, remembering your level within
312 * this game), multiplayer support for the event loop, some global variable
313 * cleanup. All that and a bag of chips!
314 *
315 * Revision 1.24 2000/09/04 19:48:02 weimer
316 * interim menu for choosing among game styles, button changes (two states)
317 *
318 * Revision 1.23 2000/09/03 19:41:30 wkiri
319 * Now allows you to choose the game type (though it doesn't do anything yet).
320 *
321 * Revision 1.22 2000/09/03 18:44:36 wkiri
322 * Cleaned up atris.c (see high_score_check()).
323 * Added game type (defaults to MARATHON).
324 *
325 * Revision 1.21 2000/09/03 18:26:10 weimer
326 * major header file and automatic prototype generation changes, restructuring
327 *
328 * Revision 1.20 2000/09/03 17:56:36 wkiri
329 * Reorganization of files (display.[ch], event.c are new).
330 *
331 * Revision 1.19 2000/08/26 03:11:34 wkiri
332 * Buttons now use borders.
333 *
334 * Revision 1.18 2000/08/26 02:45:28 wkiri
335 * Beginnings of button class; also modified atris to query for 'new
336 * game' vs. 'quit'. (New Game doesn't work yet...)
337 *
338 * Revision 1.17 2000/08/26 00:54:00 wkiri
339 * Now high-scoring user enters name at the proper place.
340 * Also, score is shown even if user doesn't make the high score list.
341 *
342 * Revision 1.16 2000/08/20 23:45:58 wkiri
343 * High scores reports the hour:minute rather than the year.
344 *
345 * Revision 1.15 2000/08/20 23:39:00 wkiri
346 * Different color for the scores in the score display; positions adjusted.
347 *
348 * Revision 1.14 2000/08/20 19:00:29 weimer
349 * text output changes (moved from _Solid to _Blended)
350 *
351 * Revision 1.13 2000/08/20 17:16:25 wkiri
352 * Can quit using 'q' and this will skip the high score list.
353 * Adjusted the high score display positions to fit in the window.
354 *
355 * Revision 1.12 2000/08/20 16:49:52 wkiri
356 * Now supports dates as well.
357 *
358 * Revision 1.11 2000/08/20 16:20:46 wkiri
359 * Now displays the new score correctly.
360 *
361 * Revision 1.10 2000/08/20 16:16:04 wkiri
362 * Better display of high scores.
363 *
364 * Revision 1.9 2000/08/15 01:58:11 wkiri
365 * Not allowed to backspace before the beginning of the array! :)
366 * Handles this gracefully (i.e. ignores any such keypresses)
367 * and clears the display correctly even when fewer letters are present
368 * than were present previously (when BS is pressed).
369 *
370 * Revision 1.8 2000/08/15 01:30:33 wkiri
371 * Handles shift keys (i.e. empty messages) properly.
372 *
373 * Revision 1.7 2000/08/15 01:22:59 wkiri
374 * High scores can handle punctuation, backspace, and spaces in names.
375 * Also, display is nicer (got rid of the weird boxes).
376 *
377 * Revision 1.6 2000/08/15 00:52:33 wkiri
378 * Ooops! Now properly checks for new high scores.
379 *
380 * Revision 1.5 2000/08/15 00:50:49 wkiri
381 * Now displays your high score name as you type it in.
382 * No support for backspace, though.
383 *
384 * Revision 1.4 2000/08/15 00:37:01 wkiri
385 * Wes found nasty memory bug! Wes is my hero!
386 * Also, changes to high scores to get input from the window.
387 *
388 * Revision 1.3 2000/08/15 00:22:15 wkiri
389 * Now handles non-regular-ascii input to high scores.
390 *
391 * Revision 1.2 2000/08/14 23:37:06 wkiri
392 * Removed debugging output from high score module.
393 *
394 * Revision 1.1 2000/08/14 01:07:17 wkiri
395 * High score files.
396 *
397 */
398
399