1 /* highscore.c
2 
3    Implementation of high score tables for tuxmath.
4 
5    Copyright 2009, 2010.
6 Authors: David Bruce, Akash Gangil, Brendan Luchen.
7 Project email: <tuxmath-devel@lists.sourceforge.net>
8 Project website: http://tux4kids.alioth.debian.org
9 
10 highscore.c is part of "Tux, of Math Command", a.k.a. "tuxmath".
11 
12 Tuxmath is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
16 
17 Tuxmath is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
24 
25 
26 
27 
28 #include "tuxmath.h"
29 #include "highscore.h"
30 #include "titlescreen.h"
31 #include "fileops.h"
32 #include "setup.h"
33 #include "options.h"
34 
35 #include <string.h>
36 
37 typedef struct high_score_entry {
38     int score;
39     char name[HIGH_SCORE_NAME_LENGTH];
40 } high_score_entry;
41 
42 
43 high_score_entry high_scores[NUM_HIGH_SCORE_LEVELS][HIGH_SCORES_SAVED];
44 
45 /* Local function prototypes: */
46 
47 
48 
49 /* Display high scores: */
DisplayHighScores(int level)50 void DisplayHighScores(int level)
51 {
52     int i = 0;
53     int finished = 0;
54     Uint32 frame = 0;
55     Uint32 timer = 0;
56 
57     int diff_level = level;
58     int old_diff_level = -1; //So table gets refreshed first time through
59     /* Surfaces, char buffers, and rects for table: */
60     SDL_Surface* score_surfs[HIGH_SCORES_SAVED] = {NULL};
61 
62     /* 10 spaces should be enough room for place and score on each line: */
63     char score_strings[HIGH_SCORES_SAVED][HIGH_SCORE_NAME_LENGTH + 10] = {{'\0'}};
64 
65     SDL_Rect score_rects[HIGH_SCORES_SAVED];
66     SDL_Rect table_bg;
67 
68     const int max_width = 300;
69     int score_table_y = 100;
70 
71     const int title_font_size = 32;
72     const int player_font_size = 14;
73 
74     while (!finished)
75     {
76 	/* Check for user events: */
77 	while (SDL_PollEvent(&event))
78 	{
79 	    switch (event.type)
80 	    {
81 		case SDL_QUIT:
82 		    {
83 			cleanup();
84 		    }
85 
86 		case SDL_MOUSEBUTTONDOWN:
87 		    /* "Stop" button - go to main menu: */
88 		    {
89 			if (T4K_inRect(stop_rect, event.button.x, event.button.y ))
90 			{
91 			    finished = 1;
92 			    playsound(SND_TOCK);
93 			}
94 
95 			/* "Left" button - go to previous page: */
96 			if (T4K_inRect(prev_rect, event.button.x, event.button.y))
97 			{
98 			    if (diff_level > CADET_HIGH_SCORE)
99 			    {
100 				diff_level--;
101 				if (Opts_GetGlobalOpt(MENU_SOUND))
102 				{
103 				    playsound(SND_TOCK);
104 				}
105 			    }
106 			}
107 
108 			/* "Right" button - go to next page: */
109 			if (T4K_inRect(next_rect, event.button.x, event.button.y ))
110 			{
111 			    if (diff_level < (NUM_HIGH_SCORE_LEVELS-1))
112 			    {
113 				diff_level++;
114 				if (Opts_GetGlobalOpt(MENU_SOUND))
115 				{
116 				    playsound(SND_TOCK);
117 				}
118 			    }
119 			}
120 			break;
121 		    }
122 
123 
124 		case SDL_KEYDOWN:
125 		    {
126 			finished = 1;
127 			playsound(SND_TOCK);
128 		    }
129 	    }
130 	}
131 
132 
133 	/* If needed, redraw: */
134 	if (diff_level != old_diff_level)
135 	{
136 	    DrawTitleScreen();
137 	    /* Draw controls: */
138 	    if (stop_button)
139 		SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
140 	    /* Draw regular or grayed-out left arrow: */
141 	    if (diff_level == CADET_HIGH_SCORE)
142 	    {
143 		if (prev_gray)
144 		    SDL_BlitSurface(prev_gray, NULL, screen, &prev_rect);
145 	    }
146 	    else
147 	    {
148 		if (prev_arrow)
149 		    SDL_BlitSurface(prev_arrow, NULL, screen, &prev_rect);
150 	    }
151 	    /* Draw regular or grayed-out right arrow: */
152 	    if (diff_level == NUM_HIGH_SCORE_LEVELS - 1)
153 	    {
154 		if (next_gray)
155 		    SDL_BlitSurface(next_gray, NULL, screen, &next_rect);
156 	    }
157 	    else
158 	    {
159 		if (next_arrow)
160 		    SDL_BlitSurface(next_arrow, NULL, screen, &next_rect);
161 	    }
162 
163 	    /* Draw background shading for table: */
164 	    table_bg.x = (screen->w)/2 - (max_width + 20)/2 + 50; //don't draw over Tux
165 	    table_bg.y = 5;
166 	    table_bg.w = max_width + 20;
167 	    table_bg.h = screen->h - 10 - images[IMG_RIGHT]->h;
168 	    T4K_DrawButton(&table_bg, 25, SEL_RGBA);
169 
170 	    /* Draw difficulty level heading: */
171 	    {
172 		SDL_Surface* srfc = NULL;
173 		SDL_Rect text_rect, button_rect;
174 
175 		srfc = T4K_BlackOutline(_("Hall Of Fame"), title_font_size, &yellow);
176 		if (srfc)
177 		{
178 		    button_rect.x = text_rect.x = (screen->w)/2 - (srfc->w)/2 + 50;
179 		    button_rect.y = text_rect.y = 10;
180 		    button_rect.w = text_rect.w = srfc->w;
181 		    button_rect.h = text_rect.h = srfc->h;
182 		    /* add margin to button and draw: */
183 		    button_rect.x -= 10;
184 		    button_rect.w += 20;
185 		    T4K_DrawButton(&button_rect, 15, 0, 0, 32, 192);
186 		    /* Now blit text and free surface: */
187 		    SDL_BlitSurface(srfc, NULL, screen, &text_rect);
188 		    SDL_FreeSurface(srfc);
189 		    srfc = NULL;
190 		}
191 
192 		switch (diff_level)
193 		{
194 		    case CADET_HIGH_SCORE:
195 			srfc = T4K_BlackOutline(_("Space Cadet"), title_font_size, &white);
196 			break;
197 		    case SCOUT_HIGH_SCORE:
198 			srfc = T4K_BlackOutline(_("Scout"), title_font_size, &white);
199 			break;
200 		    case RANGER_HIGH_SCORE:
201 			srfc = T4K_BlackOutline(_("Ranger"), title_font_size, &white);
202 			break;
203 		    case ACE_HIGH_SCORE:
204 			srfc = T4K_BlackOutline(_("Ace"), title_font_size, &white);
205 			break;
206 		    case COMMANDO_HIGH_SCORE:
207 			srfc = T4K_BlackOutline(_("Commando"), title_font_size, &white);
208 			break;
209 		    case FACTORS_HIGH_SCORE:
210 			srfc = T4K_BlackOutline(_("Factors"), title_font_size, &white);
211 			break;
212 		    case FRACTIONS_HIGH_SCORE:
213 			srfc = T4K_BlackOutline(_("Fractions"), title_font_size, &white);
214 			break;
215 		    default:
216 			srfc = T4K_BlackOutline(_("Space Cadet"), title_font_size, &white);
217 		}
218 
219 		if (srfc)
220 		{
221 		    text_rect.x = (screen->w)/2 - (srfc->w)/2 + 50;
222 		    text_rect.y += text_rect.h; /* go to bottom of first line */
223 		    text_rect.w = srfc->w;
224 		    text_rect.h = srfc->h;
225 		    SDL_BlitSurface(srfc, NULL, screen, &text_rect);
226 		    SDL_FreeSurface(srfc);
227 		    srfc = NULL;
228 		    /* note where score table will start: */
229 		    score_table_y = text_rect.y + text_rect.h;
230 		}
231 	    }
232 
233 
234 	    /* Generate and draw desired table: */
235 
236 	    for (i = 0; i < HIGH_SCORES_SAVED; i++)
237 	    {
238 		/* Get data for entries: */
239 		sprintf(score_strings[i],
240 			"%d.    %d     %s",
241 			i + 1,                  /* Add one to get common-language place number */
242 			HS_Score(diff_level, i),
243 			HS_Name(diff_level, i));
244 
245 		/* Clear out old surfaces and update: */
246 		if (score_surfs[i])               /* this should not happen! */
247 		    SDL_FreeSurface(score_surfs[i]);
248 		if (HS_Score(diff_level, i) == Opts_LastScore() && frame % 5 < 2)
249 		    score_surfs[i] = T4K_BlackOutline(N_(score_strings[i]), player_font_size, &yellow);
250 		else
251 		    score_surfs[i] = T4K_BlackOutline(N_(score_strings[i]), player_font_size, &white);
252 
253 		/* Get out if T4K_BlackOutline() fails: */
254 		if (!score_surfs[i])
255 		    continue;
256 		/* Set up entries in vertical column: */
257 		if (0 == i)
258 		    score_rects[i].y = score_table_y;
259 		else
260 		    score_rects[i].y = score_rects[i - 1].y + score_rects[i - 1].h;
261 
262 		score_rects[i].x = (screen->w)/2 - max_width/2 + 50;
263 		score_rects[i].h = score_surfs[i]->h;
264 		score_rects[i].w = max_width;
265 
266 		SDL_BlitSurface(score_surfs[i], NULL, screen, &score_rects[i]);
267 		SDL_FreeSurface(score_surfs[i]);
268 		score_surfs[i] = NULL;
269 	    }
270 	    /* Update screen: */
271 	    SDL_UpdateRect(screen, 0, 0, 0, 0);
272 
273 	    old_diff_level = diff_level;
274 	}
275 
276 	HandleTitleScreenAnimations();
277 
278 	/* Wait so we keep frame rate constant: */
279 	T4K_Throttle(20, &timer);
280 	frame++;
281     }  // End of while (!finished) loop
282 }
283 
284 
285 /* Display screen to allow player to enter name for high score table:     */
286 /* The pl_name argument *must* point to a validly allocated string array  */
287 /* at least three times HIGH_SCORE_NAME_LENGTH because UTF-8 is a         */
288 /* multibyte encoding.                                                    */
HighScoreNameEntry(char * pl_name)289 void HighScoreNameEntry(char* pl_name)
290 {
291     NameEntry(pl_name, _("You Are In The Hall of Fame!"), _("Enter Your Name:"), NULL);
292 }
293 
294 /* Get pl_name from user; other strings are text displayed by dialog: */
NameEntry(char * pl_name,const char * s1,const char * s2,const char * s3)295 void NameEntry(char* pl_name, const char* s1, const char* s2, const char* s3)
296 {
297     char UTF8_buf[HIGH_SCORE_NAME_LENGTH * 3] = {'\0'};
298 
299     SDL_Rect loc;
300     SDL_Rect redraw_rect;
301 
302     int redraw = 0;
303     int first_draw = 1;
304     int finished = 0;
305     Uint32 frame = 0;
306     Uint32 start = 0;
307     wchar_t wchar_buf[HIGH_SCORE_NAME_LENGTH + 1] = {'\0'};
308     const int NAME_FONT_SIZE = 32;
309     const int BG_Y = 100;
310     const int BG_WIDTH = 400;
311     const int BG_HEIGHT = 200;
312 
313     if (!pl_name)
314 	return;
315 
316     /* We need to get Unicode vals from SDL keysyms */
317     SDL_EnableUNICODE(SDL_ENABLE);
318 
319     DEBUGMSG(debug_highscore, "Enter NameEntry()\n" );
320 
321     DrawTitleScreen();
322 
323     /* Red "Stop" circle in upper right corner to go back to main menu: */
324     if (stop_button)
325     {
326 	SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
327     }
328 
329     /* Draw translucent background for text: */
330     {
331 	SDL_Rect bg_rect;
332 	bg_rect.x = (screen->w)/2 - BG_WIDTH/2;
333 	bg_rect.y = BG_Y;
334 	bg_rect.w = BG_WIDTH;
335 	bg_rect.h = BG_HEIGHT;
336 	T4K_DrawButton(&bg_rect, 15, REG_RGBA);
337 
338 	bg_rect.x += 10;
339 	bg_rect.y += 10;
340 	bg_rect.w -= 20;
341 	bg_rect.h = 60;
342 	T4K_DrawButton(&bg_rect, 10, SEL_RGBA);
343     }
344 
345     /* Draw headings: */
346     {
347 	SDL_Surface* surf = T4K_BlackOutline(_(s1),
348 		DEFAULT_MENU_FONT_SIZE, &white);
349 	if (surf)
350 	{
351 	    loc.x = (screen->w/2) - (surf->w/2);
352 	    loc.y = 110;
353 	    SDL_BlitSurface(surf, NULL, screen, &loc);
354 	    SDL_FreeSurface(surf);
355 	}
356 
357 	surf = T4K_BlackOutline(_(s2),
358 		DEFAULT_MENU_FONT_SIZE, &white);
359 	if (surf)
360 	{
361 	    loc.x = (screen->w/2) - (surf->w/2);
362 	    loc.y = 140;
363 	    SDL_BlitSurface(surf, NULL, screen, &loc);
364 	    SDL_FreeSurface(surf);
365 	}
366 
367 	surf = T4K_BlackOutline(_(s3),
368 		DEFAULT_MENU_FONT_SIZE, &white);
369 	if (surf)
370 	{
371 	    loc.x = (screen->w/2) - (surf->w/2);
372 	    loc.y = 170;
373 	    SDL_BlitSurface(surf, NULL, screen, &loc);
374 	    SDL_FreeSurface(surf);
375 	}
376 
377     }
378 
379     /* and update: */
380     SDL_UpdateRect(screen, 0, 0, 0, 0);
381 
382 
383     while (!finished)
384     {
385 	start = SDL_GetTicks();
386 
387 	while (SDL_PollEvent(&event))
388 	{
389 	    switch (event.type)
390 	    {
391 		case SDL_QUIT:
392 		    {
393 			cleanup();
394 		    }
395 
396 		case SDL_MOUSEBUTTONDOWN:
397 		    /* "Stop" button - go to main menu: */
398 		    {
399 			if (T4K_inRect(stop_rect, event.button.x, event.button.y ))
400 			{
401 			    finished = 1;
402 			    playsound(SND_TOCK);
403 			    break;
404 			}
405 		    }
406 		case SDL_KEYDOWN:
407 		    {
408 			DEBUGMSG(debug_highscore, "Before keypress, string is %S\tlength = %d\n",
409 				wchar_buf, (int)wcslen(wchar_buf));
410 			switch (event.key.keysym.sym)
411 			{
412 			    case SDLK_ESCAPE:
413 			    case SDLK_RETURN:
414 			    case SDLK_KP_ENTER:
415 				{
416 				    finished = 1;
417 				    playsound(SND_TOCK);
418 				    break;
419 				}
420 			    case SDLK_BACKSPACE:
421 				{
422 				    if (wcslen(wchar_buf) > 0)
423 					wchar_buf[(int)wcslen(wchar_buf) - 1] = '\0';
424 				    redraw = 1;
425 				    break;
426 				}
427 
428 				/* For any other keys, if the key has a Unicode value, */
429 				/* we add it to our string:                            */
430 			    default:
431 				{
432 				    if ((event.key.keysym.unicode > 0)
433 					    && (wcslen(wchar_buf) < HIGH_SCORE_NAME_LENGTH))
434 				    {
435 					wchar_buf[(int)wcslen(wchar_buf)] = event.key.keysym.unicode;
436 					redraw = 1;
437 				    }
438 				}
439 			}  /* end  'switch (event.key.keysym.sym)'  */
440 
441 			DEBUGMSG(debug_highscore, "After keypress, string is %S\tlength = %d\n",
442 				wchar_buf, (int)wcslen(wchar_buf));
443 			/* Now draw name, if needed: */
444 			if (redraw)
445 			{
446 			    SDL_Surface* s = NULL;
447 			    redraw = 0;
448 
449 			    /* Convert text to UTF-8 so T4K_BlackOutline() can handle it: */
450 			    //         wcstombs((char*) UTF8_buf, wchar_buf, HIGH_SCORE_NAME_LENGTH * 3);
451 			    T4K_ConvertToUTF8(wchar_buf, UTF8_buf, HIGH_SCORE_NAME_LENGTH * 3);
452 			    /* Redraw background and shading in area where we drew text last time: */
453 			    if (!first_draw)
454 			    {
455 				SDL_BlitSurface(current_bkg(), &redraw_rect, screen, &redraw_rect);
456 				T4K_DrawButton(&redraw_rect, 0, REG_RGBA);
457 				SDL_UpdateRect(screen,
458 					redraw_rect.x,
459 					redraw_rect.y,
460 					redraw_rect.w,
461 					redraw_rect.h);
462 			    }
463 
464 			    s = T4K_BlackOutline(UTF8_buf, NAME_FONT_SIZE, &yellow);
465 			    if (s)
466 			    {
467 				/* set up loc and blit: */
468 				loc.x = (screen->w/2) - (s->w/2);
469 				loc.y = 230;
470 				SDL_BlitSurface(s, NULL, screen, &loc);
471 
472 				/* Remember where we drew so we can update background next time through:  */
473 				/* (for some reason we need to update a wider area to get clean image)    */
474 				redraw_rect.x = loc.x - 20;
475 				redraw_rect.y = loc.y - 10;
476 				redraw_rect.h = s->h + 20;
477 				redraw_rect.w = s->w + 40;
478 				first_draw = 0;
479 
480 				SDL_UpdateRect(screen,
481 					redraw_rect.x,
482 					redraw_rect.y,
483 					redraw_rect.w,
484 					redraw_rect.h);
485 				SDL_FreeSurface(s);
486 				s = NULL;
487 			    }
488 			}
489 		    }
490 	    }
491 	}
492 
493 	HandleTitleScreenAnimations();
494 
495 	/* Wait so we keep frame rate constant: */
496 	while ((SDL_GetTicks() - start) < 33)
497 	{
498 	    SDL_Delay(20);
499 	}
500 	frame++;
501     }  // End of while (!finished) loop
502 
503     /* Turn off SDL Unicode lookup (because has some overhead): */
504     SDL_EnableUNICODE(SDL_DISABLE);
505 
506     /* Now copy name into location pointed to by arg: */
507     strncpy(pl_name, UTF8_buf, HIGH_SCORE_NAME_LENGTH * 3);
508 
509     DEBUGMSG(debug_highscore, "Leaving NameEntry(), final string is: %s\n",
510 	    pl_name);
511 }
512 
513 
514 
515 
516 /* Zero-out the array before use: */
initialize_scores(void)517 void initialize_scores(void)
518 {
519     int i, j;
520     for (i = 0; i < NUM_HIGH_SCORE_LEVELS; i++)
521     {
522 	for (j = 0; j < HIGH_SCORES_SAVED; j++)
523 	{
524 	    high_scores[i][j].score = 0;
525 	    strcpy(high_scores[i][j].name, "");
526 	}
527     }
528 }
529 
530 /* Test to see where a new score ranks on the list.      */
531 /* The return value is the index value - add one to get  */
532 /* the common-language place on the list.                */
check_score_place(int diff_level,int new_score)533 int check_score_place(int diff_level, int new_score)
534 {
535     int i = 0;
536 
537     /* Make sure diff_level is valid: */
538     if (diff_level < 0
539 	    || diff_level >= NUM_HIGH_SCORE_LEVELS)
540     {
541 	fprintf(stderr, "In insert_score(), diff_level invalid!\n");
542 	return 0;
543     }
544 
545     /* Find correct place in list: */
546     for (i = 0; i < HIGH_SCORES_SAVED; i++)
547     {
548 	if (new_score > high_scores[diff_level][i].score)
549 	    break;
550     }
551 
552     return i;  /* So if we return HIGH_SCORES_SAVED, the score did not */
553     /* make the list.                                       */
554 }
555 
556 /* Put a new high score entry into the table for the corresponding */
557 /* difficulty level - returns 1 if successful.                     */
insert_score(char * playername,int diff_level,int new_score)558 int insert_score(char* playername, int diff_level, int new_score)
559 {
560     int i = 0;
561     int insert_place;
562 
563     insert_place = check_score_place(diff_level, new_score);
564 
565     if (HIGH_SCORES_SAVED == insert_place) /* Score didn't make the top 10 */
566     {
567 	return 0;
568     }
569 
570     /* Move lower entries down: */
571     for (i = HIGH_SCORES_SAVED - 1; i > insert_place; i--)
572     {
573 	high_scores[diff_level][i].score =
574 	    high_scores[diff_level][i - 1].score;
575 	strncpy(high_scores[diff_level][i].name,
576 		high_scores[diff_level][i - 1].name,
577 		HIGH_SCORE_NAME_LENGTH);
578     }
579 
580     /* Now put in new entry: */
581     high_scores[diff_level][insert_place].score = new_score;
582     strncpy(high_scores[diff_level][insert_place].name,
583 	    playername,
584 	    HIGH_SCORE_NAME_LENGTH);
585     return 1;
586 }
587 
588 
print_high_scores(FILE * fp)589 void print_high_scores(FILE* fp)
590 {
591     int i, j;
592 
593     fprintf(fp, "\nHigh Scores:\n");
594 
595     for (i = 0; i < NUM_HIGH_SCORE_LEVELS; i++)
596     {
597 	switch(i)
598 	{
599 	    case CADET_HIGH_SCORE:
600 		{
601 		    fprintf(fp, "\nSpace Cadet:\n");
602 		    break;
603 		}
604 	    case SCOUT_HIGH_SCORE:
605 		{
606 		    fprintf(fp, "\nScout:\n");
607 		    break;
608 		}
609 	    case RANGER_HIGH_SCORE:
610 		{
611 		    fprintf(fp, "\nRanger:\n");
612 		    break;
613 		}
614 	    case ACE_HIGH_SCORE:
615 		{
616 		    fprintf(fp, "\nAce:\n");
617 		    break;
618 		}
619 	    case COMMANDO_HIGH_SCORE:
620 		{
621 		    fprintf(fp, "\nCommando:\n");
622 		    break;
623 		}
624 	    case FACTORS_HIGH_SCORE:
625 		{
626 		    fprintf(fp, "\nFactors:\n");
627 		    break;
628 		}
629 	    case FRACTIONS_HIGH_SCORE:
630 		{
631 		    fprintf(fp, "\nFractions:\n");
632 		    break;
633 		}
634 	}
635 
636 	for (j = 0; j < HIGH_SCORES_SAVED; j++)
637 	{
638 	    fprintf(fp, "%d.\t%s\t%d\n",
639 		    j + 1,                  //Convert to common-language ordinals
640 		    high_scores[i][j].name,
641 		    high_scores[i][j].score);
642 	}
643     }
644 }
645 
646 
read_high_scores_fp(FILE * fp)647 int read_high_scores_fp(FILE* fp)
648 {
649     char buf[PATH_MAX];
650     char* token;
651     const char delimiters[] = "\t";
652 
653     char* name_read;
654     int score_read;
655     int diff_level;
656 
657     DEBUGMSG(debug_highscore, "Entering read_high_scores_fp()\n");
658 
659     /* get out if file pointer invalid: */
660     if(!fp)
661     {
662 	fprintf(stderr, "In read_high_scores_fp(), file pointer invalid!\n");
663 	return 0;
664     }
665 
666     /* make sure we start at beginning: */
667     rewind(fp);
668 
669     /* read in a line at a time: */
670     while (fgets (buf, PATH_MAX, fp))
671     {
672 	/* Ignore comment lines: */
673 	if ((buf[0] == ';') || (buf[0] == '#'))
674 	{
675 	    continue;
676 	}
677 	/* Split up line with strtok()to get needed values,  */
678 	/* then call insert_score() for each line.           */
679 	token = strtok(buf, delimiters);
680 	if (!token)
681 	    continue;
682 	diff_level = atoi(token);
683 	if (diff_level >= NUM_HIGH_SCORE_LEVELS)
684 	    continue;
685 
686 	token = strtok(NULL, delimiters);
687 	if (!token)
688 	    continue;
689 	score_read = atoi(token);
690 	/* Note that name can contain spaces - \t is only delimiter: */
691 	name_read = strtok(NULL, delimiters);
692 	/* Now insert entry: */
693 	insert_score(name_read, diff_level, score_read);
694     }
695     return 1;
696 }
697 
698 
699 /* Return the score associated with a table entry:    */
700 /* Note: the place is given as the array index, i.e.  */
701 /* 0 for the top of the list.                         */
HS_Score(int diff_level,int place)702 int HS_Score(int diff_level, int place)
703 {
704     /* Make sure diff_level is valid: */
705     if (diff_level < 0
706 	    || diff_level >= NUM_HIGH_SCORE_LEVELS)
707     {
708 	fprintf(stderr, "In HS_Score(), diff_level = %d, invalid!\n", diff_level);
709 	return -1;
710     }
711 
712     /* Make sure place is valid: */
713     if (place < 0
714 	    || place >= HIGH_SCORES_SAVED)
715     {
716 	fprintf(stderr, "In HS_Score(), place invalid!\n");
717 	return -1;
718     }
719 
720     return high_scores[diff_level][place].score;
721 }
722 
723 
724 /* Return (pointer to) the name associated with a table entry:  */
HS_Name(int diff_level,int place)725 char* HS_Name(int diff_level, int place)
726 {
727     /* Make sure diff_level is valid: */
728     if (diff_level < 0
729 	    || diff_level >= NUM_HIGH_SCORE_LEVELS)
730     {
731 	fprintf(stderr, "In HS_Name(), diff_level invalid!\n");
732 	return NULL;
733     }
734 
735     /* Make sure place is valid: */
736     if (place < 0
737 	    || place >= HIGH_SCORES_SAVED)
738     {
739 	fprintf(stderr, "In HS_Name(), place invalid!\n");
740 	return NULL;
741     }
742 
743     return high_scores[diff_level][place].name;
744 }
745 
746 
747 
748 
749 
750 
751