1 /*
2 * XBoing - An X11 blockout style computer game
3 *
4 * (c) Copyright 1993, 1994, 1995, Justin C. Kibell, All Rights Reserved
5 *
6 * The X Consortium, and any party obtaining a copy of these files from
7 * the X Consortium, directly or indirectly, is granted, free of charge, a
8 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
9 * nonexclusive right and license to deal in this software and
10 * documentation files (the "Software"), including without limitation the
11 * rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons who receive
13 * copies from any such party to do so. This license includes without
14 * limitation a license to do the foregoing actions under any patents of
15 * the party supplying this software to the X Consortium.
16 *
17 * In no event shall the author be liable to any party for direct, indirect,
18 * special, incidental, or consequential damages arising out of the use of
19 * this software and its documentation, even if the author has been advised
20 * of the possibility of such damage.
21 *
22 * The author specifically disclaims any warranties, including, but not limited
23 * to, the implied warranties of merchantability and fitness for a particular
24 * purpose. The software provided hereunder is on an "AS IS" basis, and the
25 * author has no obligation to provide maintenance, support, updates,
26 * enhancements, or modifications.
27 */
28
29 /*
30 * =========================================================================
31 *
32 * $Id: highscore.c,v 1.1.1.1 1994/12/16 01:36:46 jck Exp $
33 * $Source: /usr5/legends/jck/xb/master/xboing/highscore.c,v $
34 * $Revision: 1.1.1.1 $
35 * $Date: 1994/12/16 01:36:46 $
36 *
37 * $Log: highscore.c,v $
38 * Revision 1.1.1.1 1994/12/16 01:36:46 jck
39 * The XBoing distribution requires configuration management. This is why the
40 * cvs utility is being used. This is the initial import of all source etc..
41 *
42 *
43 * =========================================================================
44 */
45
46 /*
47 * Include file dependencies:
48 */
49
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <stddef.h>
53 #include <ctype.h>
54 #include <unistd.h>
55 #include <time.h>
56 #include <file.h>
57 #include <sys/param.h>
58 #include <sys/stat.h>
59 #include <X11/Xlib.h>
60 #include <X11/Xutil.h>
61 #include <X11/Xos.h>
62 #include <netinet/in.h>
63 #include <xpm.h>
64
65 #include "error.h"
66 #include "misc.h"
67 #include "main.h"
68 #include "preview.h"
69 #include "audio.h"
70 #include "special.h"
71 #include "init.h"
72 #include "inst.h"
73 #include "stage.h"
74 #include "blocks.h"
75 #include "ball.h"
76 #include "sfx.h"
77 #include "score.h"
78 #include "paddle.h"
79 #include "level.h"
80 #include "mess.h"
81 #include "intro.h"
82 #include "presents.h"
83
84 #include "bitmaps/highscr.xpm"
85
86 #include "highscore.h"
87
88 /*
89 * Internal macro definitions:
90 */
91
92 #define GAP 13
93 #define NUM_HIGHSCORES 10
94
95 #ifndef MAXPATHLEN
96 #define MAXPATHLEN 1024
97 #endif
98
99 /* My locking defines only */
100 #define LOCK_FILE 0
101 #define UNLOCK_FILE 1
102
103 /* System locking defines */
104
105 #ifndef NO_LOCKING
106 #ifndef LOCK_EX
107 #define LOCK_EX F_LOCK
108 #endif
109 #ifndef LOCK_UN
110 #define LOCK_UN F_ULOCK
111 #endif
112 #endif /* NO_LOCKING */
113
114 /*
115 * Internal type declarations:
116 */
117
118 #if NeedFunctionPrototypes
119 static void SetHighScoreWait(enum HighScoreStates newMode, int waitFrame);
120 static void InitialiseHighScores(void);
121 static void SortHighScores(void);
122 static void DeleteScore(int i);
123 static int LockUnlock(int cmd, int fd);
124 #else
125 static int LockUnlock();
126 static void DeleteScore();
127 static void SetHighScoreWait();
128 static void InitialiseHighScores();
129 static void SortHighScores();
130 #endif
131
132 /*
133 * Internal variable declarations:
134 */
135
136 static int nextFrame = 0;
137 static int endFrame = 0;
138 enum HighScoreStates HighScoreState;
139 static Pixmap titlePixmap, titlePixmapM;
140 static int waitingFrame;
141 extern enum HighScoreStates waitMode;
142 static int sparkley = 0;
143 static int sindex = 0;
144 static int si = 0;
145 static int scoreType = GLOBAL;
146 static char nickName[22];
147
148 highScoreEntry highScores[NUM_HIGHSCORES];
149 highScoreHeader scoresHeader;
150
151 #if NeedFunctionPrototypes
SetNickName(char * nick)152 void SetNickName(char *nick)
153 #else
154 void SetNickName(nick)
155 char *nick;
156 #endif
157 {
158 /* Change the users nick name */
159 strncpy(nickName, nick, 20);
160 }
161
162 #if NeedFunctionPrototypes
SetBoingMasterText(char * message)163 void SetBoingMasterText(char *message)
164 #else
165 void SetBoingMasterText(message)
166 char *message;
167 #endif
168 {
169 /* Change the boing masters text */
170 strcpy(scoresHeader.masterText, message);
171 }
172
173 #if NeedFunctionPrototypes
GetNickName(void)174 char *GetNickName(void)
175 #else
176 char *GetNickName()
177 #endif
178 {
179 /* Return the nickname or NULL */
180 if (nickName[0] == '\0')
181 return NULL;
182 else
183 return nickName;
184 }
185
186 #if NeedFunctionPrototypes
SetUpHighScore(Display * display,Window window,Colormap colormap)187 void SetUpHighScore(Display *display, Window window, Colormap colormap)
188 #else
189 void SetUpHighScore(display, window, colormap)
190 Display *display;
191 Window window;
192 Colormap colormap;
193 #endif
194 {
195 XpmAttributes attributes;
196 int XpmErrorStatus;
197
198 attributes.valuemask = XpmColormap;
199 attributes.colormap = colormap;
200
201 /* Load the highscore title pixmap */
202 XpmErrorStatus = XpmCreatePixmapFromData(display, window, highscores_xpm,
203 &titlePixmap, &titlePixmapM, &attributes);
204 HandleXPMError(display, XpmErrorStatus, "InitialiseHighScore()");
205
206 /* Free the xpm pixmap attributes */
207 XpmFreeAttributes(&attributes);
208
209 /* Setup the high score table */
210 InitialiseHighScores();
211 ResetHighScore(GLOBAL);
212 }
213
214 #if NeedFunctionPrototypes
DoTitle(Display * display,Window window)215 static void DoTitle(Display *display, Window window)
216 #else
217 static void DoTitle(display, window)
218 Display *display;
219 Window window;
220 #endif
221 {
222 char string[80];
223
224 DrawStageBackground(display, window, BACKGROUND_SPACE, True);
225
226 /* Draw the highscore title */
227 RenderShape(display, window, titlePixmap, titlePixmapM,
228 59, 20, 377, 37, False);
229 RenderShape(display, window, earthPixmap, earthPixmapM,
230 PLAY_WIDTH / 2 - 200, PLAY_HEIGHT / 2 - 160, 400, 400, False);
231
232 /* Let the dudes know how to start the game */
233 strcpy(string, "Insert coin to start the game");
234 DrawShadowCentredText(display, window, textFont,
235 string, PLAY_HEIGHT - 40, tann, PLAY_WIDTH);
236
237 /* Set the message window to have the other display toggle key */
238 if (scoreType == GLOBAL)
239 SetCurrentMessage(display, messWindow,
240 "<H> - Personal Best", False);
241 else
242 SetCurrentMessage(display, messWindow,
243 "<h> - Roll of Honour", False);
244
245 SetHighScoreWait(HIGHSCORE_SHOW, frame + 10);
246 }
247
248 #if NeedFunctionPrototypes
DoHighScores(Display * display,Window window)249 static void DoHighScores(Display *display, Window window)
250 #else
251 static void DoHighScores(display, window)
252 Display *display;
253 Window window;
254 #endif
255 {
256 int i, len, plen;
257 int xr = 30;
258 int ym = 75;
259 int xs = xr + 30;
260 int xl = xs + 75;
261 int xt = xl + 40;
262 int xg = xt + 65;
263 int xn = xg + 95;
264 int y = 200;
265 char string[80];
266 char string2[80];
267 char *p;
268 time_t theTime;
269
270 /* Read the high score table */
271 if (ReadHighScoreTable(GLOBAL) == False)
272 InitialiseHighScores();
273
274 /* Draw the boing master at top of the list */
275 strcpy(string, "Boing Master");
276 DrawShadowCentredText(display, window, textFont,
277 string, ym, red, PLAY_WIDTH);
278 ym += textFont->ascent + GAP;
279
280 /* Render the boing master's name */
281 strcpy(string, highScores[0].name);
282 DrawShadowCentredText(display, window, titleFont,
283 string, ym, yellow, PLAY_WIDTH);
284 ym += textFont->ascent + GAP;
285
286 /* Render the boing master's words of wisdom */
287 strcpy(string, scoresHeader.masterText);
288 DrawShadowCentredText(display, window, dataFont,
289 string, ym, green, PLAY_WIDTH);
290 ym += textFont->ascent + GAP * 2;
291
292 /* Read the high score table */
293 if (ReadHighScoreTable(scoreType) == False)
294 InitialiseHighScores();
295
296 /* Explain that this is the roll of honour */
297 if (scoreType == GLOBAL)
298 strcpy(string, "- The Roll of Honour -");
299 else
300 strcpy(string, "- Personal Best -");
301 DrawShadowCentredText(display, window, textFont,
302 string, ym, red, PLAY_WIDTH);
303 ym += textFont->ascent + GAP;
304
305 /* Draw the titles for the highscore table */
306 strcpy(string, "#");
307 len = strlen(string);
308 DrawText(display, window, xr+2, y+2, textFont, black, string, len);
309 DrawText(display, window, xr, y, textFont, yellow, string, len);
310
311 strcpy(string, "Score");
312 len = strlen(string);
313 DrawText(display, window, xs+2, y+2, textFont, black, string, len);
314 DrawText(display, window, xs, y, textFont, yellow, string, len);
315
316 strcpy(string, "L");
317 len = strlen(string);
318 DrawText(display, window, xl+2, y+2, textFont, black, string, len);
319 DrawText(display, window, xl, y, textFont, yellow, string, len);
320
321 strcpy(string, "Time");
322 len = strlen(string);
323 DrawText(display, window, xt+2, y+2, textFont, black, string, len);
324 DrawText(display, window, xt, y, textFont, yellow, string, len);
325
326 strcpy(string, "Date");
327 len = strlen(string);
328 DrawText(display, window, xg+2, y+2, textFont, black, string, len);
329 DrawText(display, window, xg, y, textFont, yellow, string, len);
330
331 strcpy(string, "Player");
332 len = strlen(string);
333 DrawText(display, window, xn+2, y+2, textFont, black, string, len);
334 DrawText(display, window, xn, y, textFont, yellow, string, len);
335
336 y += textFont->ascent + GAP / 2;
337
338 /* Draw the line above the table */
339 DrawLine(display, window, 22, y+2, PLAY_WIDTH - 18, y+2, black, 3);
340 DrawLine(display, window, 20, y, PLAY_WIDTH - 20, y, white, 3);
341
342 y += textFont->ascent;
343
344 /* Draw the scores into the table */
345 for (i = 0; i < NUM_HIGHSCORES; i++)
346 {
347 if (ntohl(highScores[i].score) > (u_long) 0)
348 {
349 /* Draw the rank */
350 sprintf(string, "%d", i+1);
351 if (ntohl(highScores[i].score) != score)
352 DrawShadowText(display, window, textFont, string, xr, y, tann);
353 else
354 DrawShadowText(display, window, textFont, string, xr, y, green);
355
356 /* Draw the score */
357 sprintf(string, "%ld", ntohl(highScores[i].score));
358 if (ntohl(highScores[i].score) != score)
359 DrawShadowText(display, window, textFont, string, xs, y, red);
360 else
361 DrawShadowText(display, window, textFont, string, xs, y, green);
362
363 /* Write out the level reached */
364 sprintf(string, "%ld", ntohl(highScores[i].level));
365 DrawShadowText(display, window, textFont, string, xl, y, green);
366
367 /* Game duration in minutes and seconds */
368 sprintf(string, "%ld'%ld'%ld\"",
369 ntohl(highScores[i].gameTime) / 3600,
370 ntohl(highScores[i].gameTime) / 60,
371 ntohl(highScores[i].gameTime) % 60);
372
373 if (ntohl(highScores[i].score) != score)
374 DrawShadowText(display, window, textFont, string, xt, y, tann);
375 else
376 DrawShadowText(display, window, textFont, string, xt, y, green);
377
378 /* Construct the date for the highscore entry */
379 theTime = (time_t) ntohl(highScores[i].time);
380 strftime(string, 10, "%d %b %y", localtime(&theTime));
381 string[9] = '\0'; /* Just to be sure */
382 if (ntohl(highScores[i].score) != score)
383 DrawShadowText(display, window, textFont, string, xg, y, white);
384 else
385 DrawShadowText(display, window, textFont, string, xg, y, green);
386
387 /* Name of the boing master */
388 strcpy(string, highScores[i].name);
389 plen = XTextWidth(textFont, string, len);
390
391 /* Only use the first name if too big for screen */
392 if ((plen + xn) > PLAY_WIDTH)
393 {
394 /* Find the first space and null terminate there */
395 p = strchr(string, ' ');
396 *p = '\0';
397 strcpy(string2, string);
398
399 /* Draw a much smaller version of your name */
400 if (ntohl(highScores[i].score) != score)
401 DrawShadowText(display, window, textFont, string2, xn, y,
402 yellow);
403 else
404 DrawShadowText(display, window, textFont, string2, xn, y,
405 green);
406 }
407 else
408 {
409 /* Write out users name */
410 if (ntohl(highScores[i].score) != score)
411 DrawShadowText(display, window, textFont, string, xn, y,
412 yellow);
413 else
414 DrawShadowText(display, window, textFont, string, xn, y,
415 green);
416 }
417
418 }
419 else
420 {
421 /* This bit is for when the table entry is blank */
422 sprintf(string, "%d", i+1);
423 DrawShadowText(display, window, textFont, string, xr, y, tann);
424
425 /* Draw dashes for blank entries */
426 strcpy(string, "--");
427 DrawShadowText(display, window, textFont, string, xs, y, red);
428 DrawShadowText(display, window, textFont, string, xl, y, green);
429 DrawShadowText(display, window, textFont, string, xt, y, tann);
430 DrawShadowText(display, window, textFont, string, xg, y, white);
431 DrawShadowText(display, window, textFont, string, xn, y, yellow);
432 }
433
434 y += textFont->ascent + GAP;
435 }
436
437 /* Draw the line above the table */
438 DrawLine(display, window, 22, y+2, PLAY_WIDTH - 18, y+2, black, 3);
439 DrawLine(display, window, 20, y, PLAY_WIDTH - 20, y, white, 3);
440
441 SetHighScoreWait(HIGHSCORE_SPARKLE, frame + 2);
442 }
443
444 #if NeedFunctionPrototypes
DoTitleSparkle(Display * display,Window window)445 static void DoTitleSparkle(Display *display, Window window)
446 #else
447 static void DoTitleSparkle(display, window)
448 Display *display;
449 Window window;
450 #endif
451 {
452 static int sindex = 0;
453 static int delay = 30;
454
455 if ((frame % delay) == 0)
456 {
457 if (delay == 800) delay = 30;
458
459 /* Draw stars either side of high scores title */
460 RenderShape(display, window, stars[sindex], starsM[sindex],
461 25, 27, 20, 20, True);
462 RenderShape(display, window, stars[10-sindex], starsM[10-sindex],
463 PLAY_WIDTH-45, 27, 20, 20, True);
464
465 sindex++;
466 if (sindex == 11)
467 {
468 /* Clear away the stars */
469 XClearArea(display, window, 25, 27, 20, 20, False);
470 XClearArea(display, window, PLAY_WIDTH-45, 27, 20, 20, False);
471
472 sindex = 0;
473 if (delay == 30) delay = 800;
474 }
475 }
476 }
477
478 #if NeedFunctionPrototypes
DoSparkle(Display * display,Window window)479 static void DoSparkle(Display *display, Window window)
480 #else
481 static void DoSparkle(display, window)
482 Display *display;
483 Window window;
484 #endif
485 {
486 static Pixmap store; /* backing store for the sparkle */
487 static int x = 6; /* X position of the sparkle */
488
489 if (!store)
490 {
491 /* Create some backing store for the sparkle star */
492 store = XCreatePixmap(display, window, 20, 20,
493 DefaultDepth(display, XDefaultScreen(display)));
494 }
495
496 if (frame == endFrame)
497 {
498 /* Bug out of the sparkle and goto next sequence */
499 si = 0;
500 sindex = 0;
501 sparkley = 200 + textFont->ascent + 20;
502
503 /* End the sparkle and now set up for finish */
504 SetHighScoreWait(HIGHSCORE_FINISH, frame + 1);
505 return;
506 }
507
508 if (sindex == 0)
509 XCopyArea(display, window, store, gc, x, sparkley, 20, 20, 0, 0);
510
511 if (frame == nextFrame)
512 {
513 /* Draw the sparkle frame */
514 RenderShape(display, window, stars[sindex], starsM[sindex],
515 x, sparkley, 20, 20, True);
516
517
518 sindex++;
519 nextFrame = frame + 30;
520
521 /* Last frame of sparkle so reset */
522 if (sindex == 11)
523 {
524 XCopyArea(display, store, window, gc, 0, 0, 20, 20, x, sparkley);
525
526 sindex = 0;
527 nextFrame = frame + 100;
528 sparkley += textFont->ascent + GAP;
529
530 si++;
531
532 if ((ntohl(highScores[si].score) <= (u_long) 0) || (si == 10))
533 {
534 si = 0;
535 sindex = 0;
536 sparkley = 200 + textFont->ascent + 20;
537 }
538 }
539 }
540 }
541
542
543
544 #if NeedFunctionPrototypes
SetHighScoreWait(enum HighScoreStates newMode,int waitFrame)545 static void SetHighScoreWait(enum HighScoreStates newMode, int waitFrame)
546 #else
547 static void SetHighScoreWait(newMode, waitFrame)
548 enum HighScoreStates newMode;
549 int waitFrame;
550 #endif
551 {
552 waitingFrame = waitFrame;
553 waitMode = newMode;
554 HighScoreState = HIGHSCORE_WAIT;
555 }
556
557 #if NeedFunctionPrototypes
DoHighScoreWait(void)558 void DoHighScoreWait(void)
559 #else
560 void DoHighScoreWait()
561 #endif
562 {
563 /* Wait for the end frame then change mode */
564 if (frame == waitingFrame)
565 HighScoreState = waitMode;
566 }
567
568 #if NeedFunctionPrototypes
DoFinish(Display * display,Window window)569 static void DoFinish(Display *display, Window window)
570 #else
571 static void DoFinish(display, window)
572 Display *display;
573 Window window;
574 #endif
575 {
576 mode = MODE_PREVIEW;
577 HighScoreState = HIGHSCORE_TITLE;
578 ResetPreviewLevel();
579
580 if (noSound == False)
581 playSoundFile("gate", 50);
582
583 SetGameSpeed(FAST_SPEED);
584 }
585
586 #if NeedFunctionPrototypes
HighScore(Display * display,Window window)587 void HighScore(Display *display, Window window)
588 #else
589 void HighScore(display, window)
590 Display *display;
591 Window window;
592 #endif
593 {
594 /* Switch on the highscore table state */
595 switch (HighScoreState)
596 {
597 case HIGHSCORE_TITLE:
598 if (getSpecialEffects(display) == True)
599 {
600 /* Clear bffer and draw title */
601 DrawStageBackground(display, bufferWindow, BACKGROUND_SPACE,
602 True);
603 DrawStageBackground(display, window, BACKGROUND_SPACE,
604 False);
605 DoTitle(display, bufferWindow);
606 }
607 else
608 DoTitle(display, window);
609 break;
610
611 case HIGHSCORE_SHOW:
612 if (getSpecialEffects(display) == True)
613 {
614 DoHighScores(display, bufferWindow);
615 while (WindowBlindEffect(display, window));
616 }
617 else
618 DoHighScores(display, window);
619 break;
620
621 case HIGHSCORE_SPARKLE:
622 DoTitleSparkle(display, window);
623 DoSparkle(display, window);
624 if ((frame % FLASH) == 0)
625 RandomDrawSpecials(display);
626 BorderGlow(display, window);
627 break;
628
629 case HIGHSCORE_FINISH:
630 DoFinish(display, window);
631 break;
632
633 case HIGHSCORE_WAIT:
634 DoHighScoreWait();
635 break;
636
637 default:
638 break;
639 }
640 }
641
642 #if NeedFunctionPrototypes
CommandlineHighscorePrint(void)643 void CommandlineHighscorePrint(void)
644 #else
645 void CommandlineHighscorePrint()
646 #endif
647 {
648 char string[11];
649 int i;
650 time_t theTime;
651
652 InitialiseHighScores();
653
654 /* Must have table initialised with scores */
655 if (ReadHighScoreTable(GLOBAL) == False)
656 InitialiseHighScores();
657
658 /* Print out a pretty title message for scores */
659 fprintf(stdout,
660 " __ ___ __ ____ \n");
661 fprintf(stdout,
662 " / /_/ (_)__ _/ / / __/______ _______ ___\n");
663 fprintf(stdout,
664 " / __ / / _ `/ _ \\ _\\ \\/ __/ _ \\/ __/ -_|_-<\n");
665 fprintf(stdout,
666 " /_/ /_/_/\\_, /_//_/ /___/\\__/\\___/_/ \\__/___/\n");
667 fprintf(stdout,
668 " /___/ \n");
669
670 fprintf(stdout, "\nRank\tScore\t Level\tTime\tDate Name\n");
671 fprintf(stdout,
672 "----------------------------------------------------------------\n");
673
674 /* Zoom through the highscore table from the top */
675 for (i = 0; i < NUM_HIGHSCORES; i++)
676 {
677 theTime = (time_t) ntohl(highScores[i].time);
678 strftime(string, 10, "%d %b %y", localtime(&theTime));
679
680 if (ntohl(highScores[i].score) > 0)
681 {
682 /* Print out the actual record */
683 fprintf(stdout, "%d\t%ld\t %ld\t%ld'%ld'%ld\"\t%s %s\n",
684 i + 1, ntohl(highScores[i].score),
685 ntohl(highScores[i].level),
686 ntohl(highScores[i].gameTime) / 3600,
687 ntohl(highScores[i].gameTime) / 60,
688 ntohl(highScores[i].gameTime) % 60,
689 string, highScores[i].name);
690 }
691 }
692
693 /* Print a trailing line to make the table look good */
694 fprintf(stdout,
695 "----------------------------------------------------------------\n");
696 fflush(stdout);
697
698 /* Now display the personal highscore table */
699
700 InitialiseHighScores();
701
702 /* Must have table initialised with scores */
703 if (ReadHighScoreTable(PERSONAL) == False)
704 InitialiseHighScores();
705
706 /* Print out a pretty title message for scores */
707 fprintf(stdout, "\nPersonal Best\n\n");
708 fprintf(stdout, "Rank\tScore\t Level\tTime\tDate Name\n");
709 fprintf(stdout,
710 "----------------------------------------------------------------\n");
711
712 /* Zoom through the highscore table from the top */
713 for (i = 0; i < NUM_HIGHSCORES; i++)
714 {
715 theTime = (time_t) ntohl(highScores[i].time);
716 strftime(string, 10, "%d %b %y", localtime(&theTime));
717
718 if (ntohl(highScores[i].score) > 0)
719 {
720 /* Print out the actual record */
721 fprintf(stdout, "%d\t%ld\t %ld\t%ld'%ld'%ld\"\t%s %s\n",
722 i + 1, ntohl(highScores[i].score),
723 ntohl(highScores[i].level),
724 ntohl(highScores[i].gameTime) / 3600,
725 ntohl(highScores[i].gameTime) / 60,
726 ntohl(highScores[i].gameTime) % 60,
727 string, highScores[i].name);
728 }
729 }
730
731 /* Print a trailing line to make the table look good */
732 fprintf(stdout,
733 "----------------------------------------------------------------\n");
734 fflush(stdout);
735 }
736
737 #if NeedFunctionPrototypes
GetHighScoreRanking(u_long score)738 int GetHighScoreRanking(u_long score)
739 #else
740 int GetHighScoreRanking(score)
741 u_long score;
742 #endif
743 {
744 int i;
745
746 /* Must have table initialised with scores */
747 if (ReadHighScoreTable(GLOBAL) == False)
748 InitialiseHighScores();
749
750 /* Zoom through the highscore table from the top */
751 for (i = 0; i < NUM_HIGHSCORES; i++)
752 {
753 /* Is my score better than theirs */
754 if (score >= ntohl(highScores[i].score))
755 return (i + 1);
756 }
757
758 /* Not even in highscore table yet! */
759 return -1;
760 }
761
762 #if NeedFunctionPrototypes
ShiftScoresDown(int j,u_long score,u_long level,time_t gameTime,char * name)763 static void ShiftScoresDown(int j, u_long score, u_long level,
764 time_t gameTime, char *name)
765 #else
766 static void ShiftScoresDown(j, score, level, gameTime, name)
767 int j;
768 u_long score;
769 u_long level;
770 time_t gameTime;
771 char *name;
772 #endif
773 {
774 /* This function will shift all score below the index down
775 * towards the end and kill off the last dude. Sorry mate.
776 */
777 int i;
778
779 /* Move all the scores down one notch */
780 for (i = NUM_HIGHSCORES-1; i > j; i--)
781 {
782 /* Shift the scores down one notch */
783 highScores[i].score = highScores[i-1].score;
784 highScores[i].level = highScores[i-1].level;
785 highScores[i].time = highScores[i-1].time;
786 highScores[i].gameTime = highScores[i-1].gameTime;
787 highScores[i].userId = highScores[i-1].userId;
788 strcpy(highScores[i].name, highScores[i-1].name);
789 }
790
791 /* Add our new high score to the high score table */
792 highScores[j].score = htonl(score);
793 highScores[j].level = htonl(level);
794 highScores[j].gameTime = htonl(gameTime);
795 highScores[j].userId = htonl(getuid());
796 highScores[j].time = htonl(time(NULL));
797 strcpy(highScores[j].name, name);
798 }
799
800 #if NeedFunctionPrototypes
DeleteScore(int j)801 static void DeleteScore(int j)
802 #else
803 static void DeleteScore(j)
804 int j;
805 #endif
806 {
807 /* Delete the given score and shift all others up to fill in the hole */
808 int i;
809
810 /* Move all the scores down one notch */
811 for (i = j; i < NUM_HIGHSCORES-1; i++)
812 {
813 /* Shift the scores up one notch */
814 highScores[i].score = highScores[i+1].score;
815 highScores[i].level = highScores[i+1].level;
816 highScores[i].time = highScores[i+1].time;
817 highScores[i].gameTime = highScores[i+1].gameTime;
818 highScores[i].userId = highScores[i+1].userId;
819 strcpy(highScores[i].name, highScores[i+1].name);
820 }
821
822 highScores[i].score = htonl((u_long)0);
823 highScores[i].level = htonl((u_long)1);
824 highScores[i].gameTime = htonl(0);
825 highScores[i].userId = htonl(getuid());
826 highScores[i].time = htonl(time(NULL));
827 strcpy(highScores[i].name, "To be announced!");
828 }
829
830 #if NeedFunctionPrototypes
CheckAndAddScoreToHighScore(u_long score,u_long level,time_t gameTime,int type,char * message)831 int CheckAndAddScoreToHighScore(u_long score, u_long level, time_t gameTime,
832 int type, char *message)
833 #else
834 int CheckAndAddScoreToHighScore(score, level, gameTime, type, message)
835 u_long score;
836 u_long level;
837 time_t gameTime;
838 int type;
839 char *message;
840 #endif
841 {
842 int i;
843 int id = -1;
844 char name[80];
845
846 /* Lock the file for me only */
847 if (type == GLOBAL)
848 id = LockUnlock(LOCK_FILE, -1);
849
850 /* Read in the lastest scores */
851 if (ReadHighScoreTable(type) == False)
852 InitialiseHighScores();
853
854 /* Speed up by obtaining users name */
855 if (nickName[0] != '\0')
856 strcpy(name, nickName);
857 else
858 strcpy(name, getUsersFullName());
859
860 if (type == GLOBAL)
861 {
862 /* Go through the highscore table */
863 for (i = 0; i < NUM_HIGHSCORES; i++)
864 {
865 if (ntohl(highScores[i].userId) == getuid())
866 {
867 /* Can the last score be added to the highscores */
868 if (score > ntohl(highScores[i].score))
869 {
870 /* Delete and move up all old scores */
871 DeleteScore(i);
872
873 break;
874 }
875 else
876 {
877 /* Don't add as score is smaller */
878 if (id != -1)
879 id = LockUnlock(UNLOCK_FILE, id);
880 goto doUnlock;
881 }
882 }
883 } /* for */
884
885 /* Now add the new score into the table */
886 for (i = 0; i < NUM_HIGHSCORES; i++)
887 {
888 /* Can the last game be added to the highscores */
889 if (score > ntohl(highScores[i].score))
890 {
891 ShiftScoresDown(i, score, level, gameTime, name);
892
893 /* Add the boing master message if on top */
894 if (i == 0)
895 SetBoingMasterText(message);
896
897 /* Add to the highscore by writing it out */
898 (void) WriteHighScoreTable(type);
899
900 /* Unlock the file now thanks */
901 if (id != -1)
902 id = LockUnlock(UNLOCK_FILE, id);
903
904 /* Yes - it was placed in the highscore */
905 return True;
906 }
907 }
908
909 doUnlock:
910 /* Unlock the file now thanks */
911 if (id != -1)
912 id = LockUnlock(UNLOCK_FILE, id);
913
914 /* Not even a highscore - loser! */
915 return False;
916 }
917 else /* Type == PERSONAL */
918 {
919 /* Go through the highscore table */
920 for (i = 0; i < NUM_HIGHSCORES; i++)
921 {
922 /* Can the last game be added to the highscores */
923 if (score > ntohl(highScores[i].score))
924 {
925 ShiftScoresDown(i, score, level, gameTime, name);
926
927 /* Add to the highscore by writing it out */
928 (void) WriteHighScoreTable(type);
929
930 /* Yes - it was placed in the highscore */
931 return True;
932 }
933 }
934
935 /* Not even a highscore - loser! */
936 return False;
937 }
938 }
939
940 #if NeedFunctionPrototypes
SortHighScores(void)941 static void SortHighScores(void)
942 #else
943 static void SortHighScores()
944 #endif
945 {
946 int i, j;
947 highScoreEntry tempHighScore;
948
949 /*
950 * Perform a simple bubble sort of the entries. I haven't used a
951 * fancy sorting method as we have only 10 entries to sort.
952 */
953
954 for (i = 0; i < NUM_HIGHSCORES - 1; ++i)
955 {
956 for (j = NUM_HIGHSCORES - 1; j > i; --j)
957 {
958 /* Who has the higher score */
959 if (ntohl(highScores[j-1].score)
960 < ntohl(highScores[j].score))
961 {
962 /* Swap the entries around - use memcpy in future */
963 tempHighScore.score = highScores[j-1].score;
964 tempHighScore.level = highScores[j-1].level;
965 tempHighScore.gameTime = highScores[j-1].gameTime;
966 tempHighScore.userId = highScores[j-1].userId;
967 strcpy(tempHighScore.name, highScores[j-1].name);
968
969 highScores[j-1].score = highScores[j].score;
970 highScores[j-1].level = highScores[j].level;
971 highScores[j-1].gameTime = highScores[j].gameTime;
972 highScores[j-1].userId = highScores[j].userId;
973 strcpy(highScores[j-1].name, highScores[j].name);
974
975 highScores[j].score = tempHighScore.score;
976 highScores[j].level = tempHighScore.level;
977 highScores[j].gameTime = tempHighScore.gameTime;
978 highScores[j].userId = tempHighScore.userId;
979 strcpy(highScores[j].name, tempHighScore.name);
980 }
981 }
982 }
983 }
984
985 #if NeedFunctionPrototypes
InitialiseHighScores(void)986 static void InitialiseHighScores(void)
987 #else
988 static void InitialiseHighScores()
989 #endif
990 {
991 int i;
992
993 /* Setup the header structure */
994 scoresHeader.version = htonl((u_long) SCORE_VERSION);
995 SetBoingMasterText("Anyone play this game?");
996
997 /* Loop down table clearing everything out */
998 for (i = 0; i < NUM_HIGHSCORES; i++)
999 {
1000 /* Null out all entries */
1001 highScores[i].score = htonl((u_long) 0);
1002 highScores[i].level = htonl((u_long) 1);
1003 highScores[i].gameTime = htonl(0);
1004 highScores[i].userId = htonl(0);
1005 highScores[i].time = htonl(time(NULL));
1006 strcpy(highScores[i].name, "To be announced!");
1007 }
1008 }
1009
1010 #if NeedFunctionPrototypes
ReadHighScoreTable(int type)1011 int ReadHighScoreTable(int type)
1012 #else
1013 int ReadHighScoreTable(type)
1014 int type;
1015 #endif
1016 {
1017 /* Read the high score table into memory structure */
1018 FILE *hsfp;
1019 int i;
1020 char filename[MAXPATHLEN];
1021 char *str;
1022
1023 /* Are we going to use the global or personal highscore file */
1024 if (type == GLOBAL)
1025 {
1026 /* Use the environment variable if it exists */
1027 if ((str = getenv("XBOING_SCORE_FILE")) != NULL)
1028 strncpy(filename, str, sizeof(filename)-1);
1029 else
1030 strcpy(filename, HIGH_SCORE_FILE);
1031 }
1032 else
1033 sprintf(filename, "%s/.xboing-scores", GetHomeDir());
1034
1035 /* Open the high score file */
1036 if ((hsfp = fopen(filename, "r")) == NULL)
1037 {
1038 /* Cannot open the high score file */
1039 WarningMessage("Cannot open high score file for reading.");
1040 return False;
1041 }
1042
1043 /* Write the highscore header */
1044 if (fread((char*)&scoresHeader, sizeof(highScoreHeader), 1, hsfp) != 1)
1045 {
1046 if (fclose(hsfp) < 0)
1047 WarningMessage("Cannot close high score file.");
1048 return False;
1049 }
1050
1051 if (ntohl(scoresHeader.version) != (u_long) SCORE_VERSION)
1052 {
1053 WarningMessage("Old version of high score files encountered.");
1054 if (fclose(hsfp) < 0)
1055 WarningMessage("Cannot close high score file.");
1056 return False;
1057 }
1058
1059 /* Read all high score entries */
1060 for (i = 0; i < NUM_HIGHSCORES; i++)
1061 {
1062 /* Read the highscore entry */
1063 if (fread((char*)&highScores[i], sizeof(highScoreEntry), 1, hsfp) != 1)
1064 {
1065 if (fclose(hsfp) < 0)
1066 WarningMessage("Cannot close high score file.");
1067 return False;
1068 }
1069 }
1070
1071 /* Close the high score file */
1072 if (fclose(hsfp) < 0)
1073 WarningMessage("Cannot close high score file.");
1074
1075 return True;
1076 }
1077
1078
1079 #if NeedFunctionPrototypes
WriteHighScoreTable(int type)1080 int WriteHighScoreTable(int type)
1081 #else
1082 int WriteHighScoreTable(type)
1083 int type;
1084 #endif
1085 {
1086 /* write the high score table to the high score file */
1087 FILE *hsfp;
1088 int i;
1089 char filename[MAXPATHLEN];
1090 char *str;
1091
1092 /* Make sure the table is sorted */
1093 SortHighScores();
1094
1095 /* Are we going to use the global or personal highscore file */
1096 if (type == GLOBAL)
1097 {
1098 /* Use the environment variable if it exists */
1099 if ((str = getenv("XBOING_SCORE_FILE")) != NULL)
1100 strncpy(filename, str, sizeof(filename)-1);
1101 else
1102 strcpy(filename, HIGH_SCORE_FILE);
1103 }
1104 else
1105 sprintf(filename, "%s/.xboing-scores", GetHomeDir());
1106
1107 /* Open the high score file */
1108 if ((hsfp = fopen(filename, "w+")) == NULL)
1109 {
1110 /* Cannot open the high score file */
1111 WarningMessage("Cannot open high score file for writing.");
1112 return False;
1113 }
1114
1115 /* Setup the header */
1116 scoresHeader.version = htonl((u_long)SCORE_VERSION);
1117
1118 /* Write the highscore header */
1119 if (fwrite((char*)&scoresHeader, sizeof(highScoreHeader), 1, hsfp) != 1)
1120 {
1121 if (fclose(hsfp) < 0)
1122 WarningMessage("Cannot close high score file.");
1123 return False;
1124 }
1125
1126 /* Write out all high score entries */
1127 for (i = 0; i < NUM_HIGHSCORES; i++)
1128 {
1129 /* Write the highscore entry */
1130 if (fwrite((char*)&highScores[i], sizeof(highScoreEntry), 1, hsfp) != 1)
1131 {
1132 if (fclose(hsfp) < 0)
1133 WarningMessage("Cannot close high score file.");
1134 return False;
1135 }
1136 }
1137
1138 /* Close the high score file */
1139 if (fclose(hsfp) < 0)
1140 WarningMessage("Cannot close high score file.");
1141
1142 return True;
1143 }
1144
1145 #if NeedFunctionPrototypes
RedrawHighScore(Display * display,Window window)1146 void RedrawHighScore(Display *display, Window window)
1147 #else
1148 void RedrawHighScore(display, window)
1149 Display *display;
1150 Window window;
1151 #endif
1152 {
1153 /* Draw the title screen for highscore table */
1154 DoTitle(display, window);
1155 }
1156
1157 #if NeedFunctionPrototypes
FreeHighScore(Display * display)1158 void FreeHighScore(Display *display)
1159 #else
1160 void FreeHighScore(display)
1161 Display *display;
1162 #endif
1163 {
1164 /* Free up those memory leaks thanks */
1165 if (titlePixmap) XFreePixmap(display, titlePixmap);
1166 if (titlePixmapM) XFreePixmap(display, titlePixmapM);
1167 }
1168
1169 #if NeedFunctionPrototypes
ResetHighScore(int type)1170 void ResetHighScore(int type)
1171 #else
1172 void ResetHighScore(type)
1173 int type;
1174 #endif
1175 {
1176 HighScoreState = HIGHSCORE_TITLE;
1177 nextFrame = frame + 100;
1178 endFrame = frame + 4000;
1179
1180 /* Reset the sparkles for the names */
1181 sparkley = 200 + textFont->ascent + 20;
1182 sindex = 0;
1183 si = 0;
1184 scoreType = type;
1185
1186 DEBUG("Reset highscore mode.")
1187 }
1188
1189 #if NeedFunctionPrototypes
LockUnlock(int cmd,int fd)1190 static int LockUnlock(int cmd, int fd)
1191 #else
1192 static int LockUnlock(cmd)
1193 int cmd, fd;
1194 #endif
1195 {
1196 static int inter = -1;
1197 char filename[1024];
1198 char *str;
1199 int theCmd;
1200
1201
1202 #ifndef NO_LOCKING
1203
1204 /* Suss out what command to use */
1205 if (cmd == LOCK_FILE)
1206 #ifndef USE_FLOCK
1207 theCmd = F_LOCK;
1208 #else
1209 theCmd = LOCK_EX;
1210 #endif
1211 else
1212 #ifndef USE_FLOCK
1213 theCmd = F_ULOCK;
1214 #else
1215 theCmd = LOCK_UN;
1216 #endif
1217
1218 #endif /* NO_LOCKING */
1219
1220
1221 /* Use the environment variable if it exists */
1222 if ((str = getenv("XBOING_SCORE_FILE")) != NULL)
1223 strncpy(filename, str, sizeof(filename)-1);
1224 else
1225 strcpy(filename, HIGH_SCORE_FILE);
1226
1227 /* Open the highscore file for both read & write */
1228 if (cmd == LOCK_FILE)
1229 inter = open(filename, O_CREAT | O_RDWR, 0666);
1230 else
1231 /* use old fd to unlock */
1232 inter = fd;
1233
1234 #ifndef NO_LOCKING
1235
1236 /* Ok - if successful then lock or unlock the file */
1237 if (inter != -1)
1238 #ifndef USE_FLOCK
1239 lockf(inter, theCmd, sizeof(highScores));
1240 #else
1241 flock(inter, theCmd);
1242 #endif
1243
1244 #endif /* NO_LOCKING */
1245
1246
1247 /* Are we unlocking the file */
1248 if (cmd == UNLOCK_FILE)
1249 {
1250 /* Close the file now thanks */
1251 close(inter);
1252 inter = -1;
1253 }
1254
1255 /* Return success status */
1256 return inter;
1257 }
1258