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