1 /***************************************
2 $Header: /home/amb/CVS/xbomb/hiscore.c,v 1.13 2008-01-05 19:23:07 amb Exp $
3
4 XBomb - 'Minesweeper' game - Version 2.2.
5
6 Hi-score table management.
7 ******************/ /******************
8 Written by Andrew M. Bishop
9
10 This file Copyright 1994-2007 Andrew M. Bishop
11 It may be distributed under the GNU Public License, version 2, or
12 any higher version. See section COPYING of the GNU Public license
13 for conditions under which this file may be redistributed.
14 ***************************************/
15
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/types.h>
21 #include <pwd.h>
22
23 #if defined(__sun__) && !defined(__svr4__)
24 int fprintf(FILE*, const char*,...);
25 int printf(const char*, ... );
26 int sscanf(char*, const char*,...);
27 int fread(void*,unsigned int,unsigned int, FILE*);
28 int fwrite(const void*,unsigned int,unsigned int, FILE*);
29 int fclose(FILE*);
30 long time(long*);
31 #endif
32
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <time.h>
36
37 #include "xbomb.h"
38
39 /*+ The current information about the grid +*/
40 extern int grid_type, /*+ type. +*/
41 grid_level; /*+ level. +*/
42
43 /*+ The names of the different game +*/
44 extern char *levels[NLEVELS], /*+ levels (difficulty). +*/
45 *types[NTYPES]; /*+ types (grid shapes). +*/
46
47 /*+ The size of the grids +*/
48 extern int widths[NLEVELS], /*+ width in tiles. +*/
49 heights[NLEVELS], /*+ height in tiles. +*/
50 nbombs[NLEVELS]; /*+ number of bombs. +*/
51
52 /*+ The names of the high score tables. +*/
53 static char *filenames[NTYPES]={"/var/games/xbomb/xbomb6.hi",
54 "/var/games/xbomb/xbomb4.hi",
55 "/var/games/xbomb/xbomb3.hi"};
56
57 /*+ The names of the positions in the high score tables. +*/
58 static char pos[11][5]={"Top","2nd","3rd","4th","5th","6th","7th","8th","9th","10th","Lost"};
59
60 /*+ The list of hi-scores for one grid type. +*/
61 static int score[NLEVELS+1][11];
62
63 /*+ The list of hi-score usernames for one grid type. +*/
64 static char name[NLEVELS+1][11][21];
65
66 /*+ The list of hi-score dates for one grid type. +*/
67 static long date[NLEVELS+1][11];
68
69 /*+ Which of the hoigh scores in the table to highlight. +*/
70 static int which_hiscore=-1;
71
72 /*+ A structure to store the high score information in the file. +*/
73 struct score_name
74 {
75 long score; /*+ The time in milliseconds. +*/
76 char name[20]; /*+ The user name. +*/
77 long date; /*+ The time in seconds from the epoch. +*/
78 };
79
80
81 static void load_high_scores(void);
82 static void save_high_scores(void);
83
84 static void decrypt_score(struct score_name* sn);
85 static void encrypt_score(struct score_name* sn);
86
87
88 /*++++++++++++++++++++++++++++++++++++++
89 Prints the high score tables.
90 ++++++++++++++++++++++++++++++++++++++*/
91
PrintHighScores(void)92 void PrintHighScores(void)
93 {
94 int l,j;
95
96 load_high_scores();
97
98 printf("\nHigh score tables for %s\n",types[grid_type-GAME_TYPE]);
99
100 for(l=0;l<NLEVELS;l++)
101 {
102 printf("\nHigh scores for %s level (%dx%d grid of %s with %d bombs)\n",levels[l],widths[l],heights[l],types[grid_type-GAME_TYPE],nbombs[l]);
103 for(j=0;j<10;j++)
104 {
105 printf("%4s : %12s = ",pos[j],name[l][j]);
106 if(!date[l][j])
107 printf(" SLOW");
108 else if(l==0)
109 printf("%6.2f",(double)score[l][j]/1000.0);
110 else if(l==1)
111 printf("%6.1f",(double)score[l][j]/1000.0);
112 else
113 printf("%6.0f",(double)score[l][j]/1000.0);
114 if(date[l][j])
115 printf(" : %s",ctime(&date[l][j]));
116 else
117 {printf(" : Never\n");break;}
118 }
119 printf("\n");
120 }
121 }
122
123
124 /*++++++++++++++++++++++++++++++++++++++
125 Adds a high score to the table if it is good enough.
126
127 int ticks The time that was taken.
128 ++++++++++++++++++++++++++++++++++++++*/
129
AddHighScore(int ticks)130 void AddHighScore(int ticks)
131 {
132 int j;
133 int changed=-1;
134 struct passwd *pwd;
135 char *username;
136
137 load_high_scores();
138
139 pwd=getpwuid(geteuid());
140 if(pwd)
141 username=pwd->pw_name;
142 else
143 username="?unknown?";
144
145 which_hiscore=10;
146 score[grid_level-GAME_LEVEL][10]=ticks;
147 strcpy(name[grid_level-GAME_LEVEL][10],username);
148 date[grid_level-GAME_LEVEL][10]=time(NULL);
149
150 for(j=0;j<10;j++)
151 if(ticks<score[grid_level-GAME_LEVEL][j])
152 {changed=which_hiscore=j;break;}
153
154 if(changed!=-1)
155 {
156 for(j=9;j>changed;j--)
157 {
158 score[grid_level-GAME_LEVEL][j]=score[grid_level-GAME_LEVEL][j-1];
159 strcpy(name[grid_level-GAME_LEVEL][j],name[grid_level-GAME_LEVEL][j-1]);
160 date[grid_level-GAME_LEVEL][j]=date[grid_level-GAME_LEVEL][j-1];
161 }
162 score[grid_level-GAME_LEVEL][changed]=ticks;
163 strcpy(name[grid_level-GAME_LEVEL][changed],username);
164 date[grid_level-GAME_LEVEL][changed]=time(NULL);
165
166 save_high_scores();
167 }
168 }
169
170
171 /*++++++++++++++++++++++++++++++++++++++
172 Select a set of high scores for display.
173 ++++++++++++++++++++++++++++++++++++++*/
174
ShowHighScores(void)175 void ShowHighScores(void)
176 {
177 char datestr[11][32],*scores[11][4],scorestr[11][10];
178 int i;
179
180 load_high_scores();
181
182 for(i=0;i<11;i++)
183 {
184 if(i==10 && which_hiscore!=10)
185 {scores[i][0]=scores[i][1]=scores[i][2]=scores[i][3]="";continue;}
186
187 strcpy(datestr[i],ctime(&date[grid_level-GAME_LEVEL][i]));
188
189 scores[i][0]=pos[i];
190
191 scores[i][1]=name[grid_level-GAME_LEVEL][i];
192
193 if(!date[grid_level-GAME_LEVEL][i])
194 scores[i][2]="SLOW";
195 else if(grid_level==GAME_EASY)
196 {sprintf(scorestr[i],"%6.2f",(double)score[grid_level-GAME_LEVEL][i]/1000.0);scores[i][2]=scorestr[i];}
197 else if(grid_level==GAME_MEDIUM)
198 {sprintf(scorestr[i],"%6.1f",(double)score[grid_level-GAME_LEVEL][i]/1000.0);scores[i][2]=scorestr[i];}
199 else
200 {sprintf(scorestr[i],"%6.0f",(double)score[grid_level-GAME_LEVEL][i]/1000.0);scores[i][2]=scorestr[i];}
201
202 if(date[grid_level-GAME_LEVEL][i])
203 scores[i][3]=datestr[i];
204 else
205 scores[i][3]="Never";
206 }
207
208 DisplayHighScores(scores,which_hiscore);
209
210 which_hiscore=-1;
211 }
212
213
214 /*++++++++++++++++++++++++++++++++++++++
215 Load in the high score table.
216 ++++++++++++++++++++++++++++++++++++++*/
217
load_high_scores(void)218 static void load_high_scores(void)
219 {
220 FILE *f;
221 int i,j;
222 struct score_name sn;
223
224 for(i=0;i<NLEVELS;i++)
225 for(j=0;j<10;j++)
226 {
227 score[i][j]=9999999;
228 strcpy(name[i][j],"nobody");
229 date[i][j]=0;
230 }
231
232 f=fopen(filenames[grid_type-GAME_TYPE],"r");
233
234 if(!f)
235 {
236 fprintf(stderr,"XBomb: Cannot open high score table '%s' to read.\n",filenames[grid_type-GAME_TYPE]);
237 return;
238 }
239
240 for(i=0;i<NLEVELS;i++)
241 for(j=0;j<10;j++)
242 {
243 if(!fread(&sn,sizeof(sn),1,f))
244 break;
245 decrypt_score(&sn);
246 score[i][j]=sn.score;
247 strcpy(name[i][j],sn.name);
248 date[i][j]=sn.date;
249 }
250
251 fclose(f);
252 }
253
254
255 /*++++++++++++++++++++++++++++++++++++++
256 Saves the high score table.
257 ++++++++++++++++++++++++++++++++++++++*/
258
save_high_scores(void)259 static void save_high_scores(void)
260 {
261 FILE *f;
262 int i,j;
263 struct score_name sn;
264
265 f=fopen(filenames[grid_type-GAME_TYPE],"w");
266
267 if(!f)
268 {
269 fprintf(stderr,"XBomb: Cannot open high score table '%s' to write.\n",filenames[grid_type-GAME_TYPE]);
270 return;
271 }
272
273 for(i=0;i<NLEVELS;i++)
274 for(j=0;j<10;j++)
275 {
276 sn.score=score[i][j];
277 strcpy(sn.name,name[i][j]);
278 sn.date=date[i][j];
279 encrypt_score(&sn);
280 fwrite(&sn,sizeof(sn),1,f);
281 }
282
283 fclose(f);
284
285 chmod(filenames[grid_type-GAME_TYPE],S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
286 }
287
288
289 /*++++++++++++++++++++++++++++++++++++++
290 Decrypts the high score table
291
292 struct score_name* sn The score and name to decrypt.
293 ++++++++++++++++++++++++++++++++++++++*/
294
decrypt_score(struct score_name * sn)295 static void decrypt_score(struct score_name* sn)
296 {
297 int i;
298 char *p=(char*)sn;
299
300 for(i=0;i<sizeof(struct score_name);i++)
301 p[i]^=125;
302
303 return;
304 }
305
306
307 /*++++++++++++++++++++++++++++++++++++++
308 Encrypts the high score table
309
310 struct score_name* sn The score and name to encrypt.
311 ++++++++++++++++++++++++++++++++++++++*/
312
encrypt_score(struct score_name * sn)313 static void encrypt_score(struct score_name* sn)
314 {
315 int i;
316 char *p=(char*)sn;
317
318 for(i=0;i<sizeof(struct score_name);i++)
319 p[i]^=125;
320
321 return;
322 }
323