1 /* $Id: highscore.c,v 1.2 1998/04/30 05:11:55 mrogre Exp $ */
2 /* Copyright (c) 1998 Joe Rumsey (mrogre@mediaone.net) */
3 #include "copyright.h"
4
5 #include <config.h>
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #ifdef HAVE_UNISTD_H
11 # include <unistd.h>
12 #endif
13 #include <sys/stat.h>
14 #ifdef HAVE_FCNTL_H
15 # include <fcntl.h>
16 #endif
17 #include <ctype.h>
18 #include <pwd.h>
19 #include <string.h>
20 #ifdef _AIX
21 #include <net/nh.h>
22 #else /* This is for ntohl, htonl.
23 This file is correct for hpux and linux for sure,
24 probably others as well. */
25 #include <netinet/in.h>
26 #endif
27
28 #include "Wlib.h"
29 #include "defs.h"
30 #include "struct.h"
31 #include "proto.h"
32 #include "data.h"
33
34 /* Global score file is insecure and rather useless today. */
35 #define NO_GLOBAL_SCORES 1
36 #ifdef NO_GLOBAL_SCORES
37 #define NUM_GLOBAL_SCORES 0
38 #else
39 #define NUM_GLOBAL_SCORES 20
40 #endif
41 #define NUM_MY_SCORES 10
42
43 static char new_name[20];
44 static int nnpos=0;
45 static int thisplace = -1, my_thisplace = -1;
46
47 static struct high_score {
48 #ifdef NOSCOREHOGS
49 long uid;
50 #endif
51 char name[20];
52 long score;
53 long level;
54 }
55 #ifndef NO_GLOBAL_SCORES
56 global_scores[NUM_GLOBAL_SCORES],
57 #endif
58 my_scores[NUM_MY_SCORES];
59
undo_name()60 void undo_name()
61 {
62 W_ClearArea(baseWin,
63 WINWIDTH/2-(20*W_Textwidth), 250,
64 (40*W_Textwidth), W_Textheight*2);
65 }
66
do_name()67 void do_name()
68 {
69 char buf[21];
70 static int init = 0;
71
72 if(!init) {
73 strcpy(new_name, getUsersFullName());
74 nnpos = strlen(new_name);
75 init = 1;
76 }
77 center_text("Great score! Enter your name:", 250, W_Red);
78 sprintf(buf, "%s_", new_name);
79 center_text(buf, 250 + W_Textheight, W_Cyan);
80 }
81
getUsersFullName()82 char *getUsersFullName()
83 {
84 struct passwd *pass;
85 char *comma;
86 char *cp1, *cp2;
87 static char fullname[80];
88
89 /* Get user information from password file */
90 if (!(pass = getpwuid(getuid())))
91 return("Anonymous?"); /* Unknown user oops. */
92
93 /* find a comma indicating further info after name */
94 comma = strchr(pass->pw_gecos, ',');
95
96 /* NULL out the comma */
97 if (comma) *comma = '\0';
98
99 /* Use the nickname if not null otherwise password file name */
100 cp1 = pass->pw_gecos;
101 cp2 = fullname;
102
103 /* Search through the gecos field looking for an '&' which on very
104 * old UNIX systems is supposed to be the users user name with the
105 * first letter uppercased.
106 */
107 while(*cp1)
108 {
109 /* Look for the '&' symbol */
110 if(*cp1 != '&')
111 *cp2++ = *cp1++;
112 else
113 {
114 /* A ha. Now copy the users name to be in place of '&' */
115 strcpy(cp2, pass->pw_name);
116
117 /* Convert the first letter to uppercase. */
118 if(islower(*cp2))
119 *cp2 = toupper(*cp2);
120
121 /* Continue with the remaining string */
122 while(*cp2) cp2++;
123 cp1++;
124 }
125 }
126
127 /* shorten to 20 chars */
128 fullname[19] = 0;
129
130 /* Return their name without any trailing stuff */
131 return(fullname);
132 }
133
save_scores()134 static void save_scores()
135 {
136 int i;
137 int hsf;
138 long x;
139 char my_file_name [256], *home;
140 #ifndef NO_GLOBAL_SCORES
141 hsf = open(SCOREFILE, O_WRONLY | O_TRUNC | O_CREAT, 0666);
142 if(hsf < 0) {
143 printf("Couldn't write scores file %s\n", SCOREFILE);
144 return;
145 }
146
147 for(i=0;i<NUM_GLOBAL_SCORES;i++) {
148 #ifdef NOSCOREHOGS
149 x=htonl(global_scores[i].uid);
150 if(write(hsf, &x, sizeof(long)) < sizeof(long))
151 goto error;
152 #endif
153 if(write(hsf, global_scores[i].name, 20) < 20)
154 goto error;
155 x=htonl(global_scores[i].score);
156 if(write(hsf, &x, sizeof(long)) < sizeof(long))
157 goto error;
158 x=htonl(global_scores[i].level);
159 if(write(hsf, &x, sizeof(long)) < sizeof(long))
160 goto error;
161 }
162 close(hsf);
163 #endif /* NO_GLOBAL_SCORES */
164 if((home = getenv("HOME"))) {
165 #ifndef NO_GLOBAL_SCORES
166 gid_t my_egid = getegid();
167 if (setgid(getgid()) != 0) {
168 perror("setgid");
169 return;
170 }
171 #endif
172 snprintf(my_file_name, sizeof(my_file_name)-1, "%s/.xgalscores", home);
173 hsf = open(my_file_name, O_WRONLY | O_TRUNC | O_CREAT, 0644);
174 #ifndef NO_GLOBAL_SCORES
175 if (setgid(my_egid) != 0) {
176 perror("setgid back");
177 exit(1);
178 }
179 #endif
180 if(hsf < 0) {
181 printf("Couldn't write scores file %s\n", my_file_name);
182 return;
183 }
184 for(i=0;i<NUM_MY_SCORES;i++) {
185 if(write(hsf, my_scores[i].name, 20) < 20)
186 goto error2;
187 x=htonl(my_scores[i].score);
188 if(write(hsf, &x, sizeof(long)) < sizeof(long))
189 goto error2;
190 x=htonl(my_scores[i].level);
191 if(write(hsf, &x, sizeof(long)) < sizeof(long))
192 goto error2;
193 }
194 close(hsf);
195 }
196
197 return;
198 #ifndef NO_GLOBAL_SCORES
199 error:
200 printf("Error saving high scores file %s\n", SCOREFILE);
201 return;
202 #endif
203 error2:
204 printf("Error saving high scores file %s\n", my_file_name);
205 return;
206 }
207
add_score(char * name,int score)208 void add_score(char *name, int score)
209 {
210 int i,j ; /* ,k; */
211
212 thisplace = my_thisplace = -1;
213
214 load_scores();
215
216 #ifndef NO_GLOBAL_SCORES
217 #ifdef NOSCOREHOGS
218 /* /lib 27jul95: want to allow only one global high-score per person,
219 * by uid (getuid)
220 */
221 for(i=0;i<NUM_GLOBAL_SCORES;i++) {
222 if(score > global_scores[i].score) {
223 /* /lib 27jul95 uniq-global-highscore: */
224 /* find old position of high-score: */
225 for(k=i;k<NUM_GLOBAL_SCORES;k++) {
226 if(global_scores[k].uid == getuid()) {
227 break;
228 }
229 }
230 if(k==NUM_GLOBAL_SCORES) {
231 k--;
232 }
233 /* found old pos, copy from i..k-1 to i+1..k */
234 for(j=k;j>i;j--) {
235 global_scores[j].uid = global_scores[j-1].uid;
236 strcpy(global_scores[j].name, global_scores[j-1].name);
237 global_scores[j].score = global_scores[j-1].score;
238 global_scores[j].level = global_scores[j-1].level;
239 }
240 global_scores[i].uid = getuid();
241 strcpy(global_scores[i].name, name);
242 global_scores[i].score = score;
243 global_scores[i].level = level;
244 thisplace = i;
245 break;
246 }
247 /* high-score stuff by /lib (uid is found, score is too low): */
248 else if(global_scores[i].uid == getuid()) {
249 break;
250 }
251 }
252
253 #else /* NOSCOREHOGS */
254 for(i=0;i<NUM_GLOBAL_SCORES;i++) {
255 if(score > global_scores[i].score) {
256 for(j=NUM_GLOBAL_SCORES-1;j>i;j--) {
257 strcpy(global_scores[j].name, global_scores[j-1].name);
258 global_scores[j].score = global_scores[j-1].score;
259 global_scores[j].level = global_scores[j-1].level;
260 }
261 strcpy(global_scores[i].name, name);
262 global_scores[i].score = score;
263 global_scores[i].level = level;
264 thisplace = i;
265 break;
266 }
267 }
268 #endif /* NOSCOREHOGS */
269 #endif /* NO_GLOBAL_SCORES */
270
271 for(i=0;i<NUM_MY_SCORES;i++) {
272 if(score > my_scores[i].score) {
273 for(j=NUM_MY_SCORES-1;j>i;j--) {
274 strcpy(my_scores[j].name, my_scores[j-1].name);
275 my_scores[j].score = my_scores[j-1].score;
276 my_scores[j].level = my_scores[j-1].level;
277 }
278 strcpy(my_scores[i].name, name);
279 my_scores[i].score = score;
280 my_scores[i].level = level;
281 my_thisplace = i;
282 break;
283 }
284 }
285 save_scores();
286 }
287
score_key(W_Event * ev)288 int score_key(W_Event *ev)
289 {
290 if(getting_name) {
291 switch(ev->key) {
292 case 13:
293 case 10:
294 case 269:
295 getting_name = 0;
296 add_score(new_name, score);
297 title_page = 1;
298 pagetimer = 300;
299 W_ClearWindow(baseWin);
300 break;
301 case 8:
302 case 127:
303 case 264:
304 if(nnpos > 0) {
305 nnpos--;
306 new_name[nnpos] = 0;
307 }
308 break;
309 case 'u'+128:
310 nnpos = 0;
311 new_name[nnpos] = 0;
312 break;
313 default:
314 if(nnpos < 19) {
315 new_name[nnpos++] = ev->key;
316 new_name[nnpos] = 0;
317 }
318 break;
319 }
320
321 return 1;
322 }
323 return 0;
324 }
325
326
check_score(int score)327 int check_score(int score)
328 {
329 int i;
330
331 load_scores(); /* in case someone else has gotten a high score */
332 #ifndef NO_GLOBAL_SCORES
333 for(i=0;i<NUM_GLOBAL_SCORES;i++) {
334 if(score > global_scores[i].score) {
335 return 1;
336 }
337 #ifdef NOSCOREHOGS
338 if(global_scores[i].uid == getuid()) {
339 break;
340 }
341 #endif
342 }
343 #endif /* NO_GLOBAL_SCORES */
344 for(i=0;i<NUM_MY_SCORES;i++) {
345 if(score > my_scores[i].score)
346 return 1;
347 }
348
349 my_thisplace = -1;
350 thisplace = -1;
351 return 0;
352 }
353
354
show_scores()355 void show_scores()
356 {
357 int i;
358 char buf[60];
359 W_Color color;
360
361 W_SetRGB16(W_DarkGrey, random()%65535,random()%65535,random()%65535);
362
363 color = W_DarkGrey;
364
365
366 #ifndef NO_GLOBAL_SCORES
367 center_text("Global high scores", 90, W_Yellow);
368 sprintf(buf, "Rank Name Score Level");
369 center_text(buf, 100, W_Yellow);
370 W_MakeLine(baseWin, WINWIDTH/2-((strlen(buf)*W_Textwidth)/2), 111,
371 WINWIDTH/2 + ((strlen(buf)*W_Textwidth)/2), 111, W_Red);
372 for(i=0;i<NUM_GLOBAL_SCORES;i++) {
373 sprintf(buf, " %2d. %-20s %7ld %5ld", i+1,
374 global_scores[i].name, global_scores[i].score,global_scores[i].level);
375 center_text(buf, 112+i*W_Textheight, (i==thisplace ? color : W_Grey));
376 }
377 #endif
378
379 center_text("Your high scores", 112+NUM_GLOBAL_SCORES*W_Textheight, W_Yellow);
380 sprintf(buf, "Rank Name Score Level");
381 center_text(buf, 112+(NUM_GLOBAL_SCORES+1)*W_Textheight, W_Yellow);
382 W_MakeLine(baseWin, WINWIDTH/2-((strlen(buf)*W_Textwidth)/2), 123+(NUM_GLOBAL_SCORES+1)*W_Textheight,
383 WINWIDTH/2 + ((strlen(buf)*W_Textwidth)/2), 123+(NUM_GLOBAL_SCORES+1)*W_Textheight, W_Red);
384 for(i=0;i<NUM_MY_SCORES;i++) {
385 sprintf(buf, " %2d. %-20s %7ld %5ld", i+1,
386 my_scores[i].name, my_scores[i].score,my_scores[i].level);
387 center_text(buf, 124+(NUM_GLOBAL_SCORES+1)*W_Textheight + i*W_Textheight,
388 (i==my_thisplace ? color : W_Grey));
389 }
390 }
391
load_scores()392 void load_scores()
393 {
394 int i;
395 int hsf;
396 char my_file_name[256], *home;
397
398 #ifndef NO_GLOBAL_SCORES
399 hsf = open(SCOREFILE, O_RDONLY);
400 if(hsf <0 ) {
401 printf("Trouble opening high scores file '%s'\n", SCOREFILE);
402 for(i=0;i<NUM_GLOBAL_SCORES;i++) {
403 #ifdef NOSCOREHOGS
404 global_scores[i].uid = 0;
405 #endif
406 global_scores[i].name[0]=0;
407 global_scores[i].score = 0;
408 global_scores[i].level = 0;
409 }
410 } else {
411 for(i=0;i<NUM_GLOBAL_SCORES;i++) {
412 #ifdef NOSCOREHOGS
413 if(read(hsf, &global_scores[i].uid, sizeof(long)) < sizeof(long))
414 goto error;
415 #endif
416 if(read(hsf, global_scores[i].name, 20) < 20)
417 goto error;
418 if(read(hsf, &global_scores[i].score, sizeof(long)) < sizeof(long))
419 goto error;
420 if(read(hsf, &global_scores[i].level, sizeof(long)) < sizeof(long))
421 goto error;
422 #ifdef NOSCOREHOGS
423 global_scores[i].uid = ntohl(global_scores[i].uid);
424 #endif
425 global_scores[i].score = ntohl(global_scores[i].score);
426 global_scores[i].level = ntohl(global_scores[i].level);
427 }
428 }
429 close(hsf);
430 #endif /* NO_GLOBAL_SCORES */
431
432 if((home = getenv("HOME"))) {
433 snprintf(my_file_name, sizeof(my_file_name)-1, "%s/.xgalscores", home);
434 hsf = open(my_file_name, O_RDONLY);
435 if(hsf <0 ) {
436 printf("Trouble opening high scores file '%s'\n", my_file_name);
437 for(i=0;i<NUM_MY_SCORES;i++) {
438 my_scores[i].name[0]=0;
439 my_scores[i].score = 0;
440 my_scores[i].level = 0;
441 }
442 } else {
443 for(i=0;i<NUM_MY_SCORES;i++) {
444 if(read(hsf, my_scores[i].name, 20) < 20)
445 goto error2;
446 if(read(hsf, &my_scores[i].score, sizeof(long)) < sizeof(long))
447 goto error2;
448 if(read(hsf, &my_scores[i].level, sizeof(long)) < sizeof(long))
449 goto error2;
450 my_scores[i].score = ntohl(my_scores[i].score);
451 my_scores[i].level = ntohl(my_scores[i].level);
452 }
453 }
454 close(hsf);
455 } else {
456 printf("No HOME variable, so no personal score file.\n");
457 for(i=0;i<NUM_MY_SCORES;i++) {
458 my_scores[i].name[0]=0;
459 my_scores[i].score = 0;
460 my_scores[i].level = 0;
461 }
462 }
463 return;
464 #ifndef NO_GLOBAL_SCORES
465 error:
466 if(i>0)
467 printf("Error reading high scores file '%s'\n", SCOREFILE);
468 for(i=0;i<NUM_GLOBAL_SCORES;i++) {
469 #ifdef NOSCOREHOGS
470 global_scores[i].uid = 0;
471 #endif
472 global_scores[i].name[0]=0;
473 global_scores[i].score = 0;
474 global_scores[i].level = 0;
475 }
476 close(hsf);
477 return;
478 #endif
479 error2:
480 if(i>0)
481 printf("Error reading high scores file '%s'\n", my_file_name);
482 for(i=0;i<NUM_MY_SCORES;i++) {
483 my_scores[i].name[0]=0;
484 my_scores[i].score = 0;
485 my_scores[i].level = 0;
486 }
487 close(hsf);
488 }
489
print_scores()490 void print_scores() {
491 int i;
492
493 load_scores();
494 #ifndef NO_GLOBAL_SCORES
495 printf("\nGlobal High Scores:\n");
496 printf("-----------------------------------------------\n");
497 printf("%8s %-20s %8s %8s\n", "uid", "name", "score", "level");
498 printf("-----------------------------------------------\n");
499 for(i=0;i<NUM_GLOBAL_SCORES;i++) {
500 if(global_scores[i].score == 0)
501 break;
502 #ifdef NOSCOREHOGS
503 printf("%8ld %-20s %8ld %8ld\n", global_scores[i].uid,
504 global_scores[i].name, global_scores[i].score,
505 global_scores[i].level);
506 #else
507 printf(" -- %-20s %8ld %8ld\n",
508 global_scores[i].name, global_scores[i].score,
509 global_scores[i].level);
510 #endif
511 }
512 #endif /* NO_GLOBAL_SCORES */
513 printf("-----------------------------------------------\n");
514 printf("\nYour High Scores:\n");
515 printf("--------------------------------------\n");
516 printf("%-20s %8s %8s\n", "name", "score", "level");
517 printf("--------------------------------------\n");
518 for(i=0;i<NUM_MY_SCORES;i++) {
519 if(my_scores[i].score == 0)
520 break;
521 printf("%-20s %8ld %8ld\n", my_scores[i].name,
522 my_scores[i].score, my_scores[i].level);
523 }
524 printf("--------------------------------------\n");
525 }
526