1 /* file scores.c */
2 /***************************************************************************
3 *  Copyright 2003 -   Steven Shipway <steve@cheshire.demon.co.uk>          *
4 *                     Put "nospam" in subject to avoid spam filter         *
5 *                                                                          *
6 *  This program is free software; you can redistribute it and/or modify    *
7 *  it under the terms of the GNU General Public License as published by    *
8 *  the Free Software Foundation; either version 2 of the License, or       *
9 *  (at your option) any later version.                                     *
10 *                                                                          *
11 *  This program is distributed in the hope that it will be useful,         *
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of          *
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
14 *  GNU General Public License for more details.                            *
15 *                                                                          *
16 *  You should have received a copy of the GNU General Public License       *
17 *  along with this program; if not, write to the Free Software             *
18 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA               *
19 *  02111-1307, USA.                                                        *
20 ***************************************************************************/
21 
22 
23 #include "wand_head.h"
24 
25 #ifdef  MSDOS        /* M001 */
26 
27 #define LOCK
28 #define UNLOCK
29 
30 #else
31 /*#define LOCK     flock( fp->_cnt , LOCK_EX ) /* peeked at stdio.h ! */
32 /*#define UNLOCK   flock( fp->_cnt , LOCK_UN ) /*                     */
33 /* #define LOCK while((lock = creat(LOCKFILE,0))==-1) Not a good way  */
34 
35 #define LOCK if((lock = open(LOCKFILE, O_CREAT | O_TRUNC | O_WRONLY, "r"))==-1){errx (1,"%s","Lockfile creation failed\n"); exit(1);} /* Marina */
36 
37 #define UNLOCK unlink(LOCKFILE)
38 
39 #endif
40 
41 #ifndef   MSDOS        /* M001 */
42 extern int getuid();
43 #else
44 #define   getuid()        0
45 #endif
46 
47 #ifdef    COMPARE_BY_NAME
48 #define   SAMEUSER(p)        (strcmp((p)->name, name) == 0)
49 #else
50 #define   SAMEUSER(p)        ((p)->uid == user_id)
51 #endif
52 
53 extern int saved_game;  /* prevent recording of hiscore if  */
54                         /* NO_RESTORED_GAME_HISCORES is #def'd */
55 
56 /***********************************
57 *       score_entry structure      *
58 ************************************/
59 typedef struct
60 {
61     char howdead[25];
62     char name[20];
63     int  score;
64     int  level;
65     int  uid;
66 } score_entry;
67 
68 #ifdef LINT_ARGS  /* M001 */
69 void show_scores(score_entry *,int );
70 int readtable(score_entry *);
71 #else
72 void show_scores();
73 int readtable();
74 #endif
75 
76 /**/
77 /************************
78 *      show_scores      *
79 *************************/
show_scores(score_entry * table,int num)80 void show_scores(score_entry *table,int num)
81 {
82     int tot = num;
83 
84     printf("\nNo. Score Level           Names                 How they died\n");
85     printf("=============================================================================\n");
86     while(num > 0)
87     {
88         num--;
89         printf("%2d %5d %3d      %-20s     killed by %-s\n",(tot - num),table->score,table->level,table->name,table->howdead);
90         table++;
91     }
92     printf("\n\n");
93 }
94 
95 /**/
96 /*************************
97 *   readtable function   *
98 **************************/
readtable(score_entry * table_ptr)99 int readtable(score_entry *table_ptr)
100 {
101     FILE *fp;
102     int  numread;
103 
104     if((fp = fopen(HISCOREPATH,R_BIN)) == NULL)
105     {
106         numread = 0;
107     }
108     else
109     {
110         numread = fread( VOIDSTAR table_ptr, sizeof(score_entry), ENTRIES, fp);
111         fclose(fp);
112     }
113     return numread;
114 }
115 
116 /**/
117 /********************
118 *     savescore     *
119 *********************/
120 
savescore(char * howdead,int score,int level,char * name)121 int  savescore(char *howdead,int score,int level,char *name)
122 {
123     score_entry table[ENTRIES + 2],
124                 *table_ptr = table,
125                 new_entry,
126                 temp_entry;
127     int numread;
128     int index = 1;
129     int numsaved;
130     int lock;
131     int already = 0;
132     int output_value = 1;
133     int user_id;
134     int position;
135 
136     FILE *fp;
137 
138 #ifdef NO_RESTORED_GAME_HISCORES
139 
140     if(saved_game)
141     {
142         printf("No hiscores recorded from restored games.\n");
143         printf("\nWanderer (C) 1988  S.Shipway.\n\n");
144         return 1;
145     }
146 #endif
147 
148     user_id = getuid();
149     strncpy(new_entry.howdead,howdead,25);
150     new_entry.howdead[24] = '\0'; /* M002 strncpy does not null terminate */
151     strncpy(new_entry.name,name,20);
152     new_entry.name[19] = '\0'; /* M002 strncpy does not null terminate */
153     new_entry.score = score;
154     new_entry.level = level;
155     new_entry.uid = user_id;
156     LOCK;    /* BUG is HERE !!! */
157     numread = readtable(table_ptr);
158     if (numread > 0)
159         if(table[numread-1].score > 99999) /* stop system errors messing it up*/
160         {
161             numread--;
162             printf("Erasing spurious entry in table.\n");
163         }
164     if(score == -1)
165     {
166         show_scores(table,numread);
167         UNLOCK;
168         return 0;
169     }
170 /* HERE */
171     if (numread > 0)
172     {
173         numread++; /* scan through until correct insertion point */
174         /* pass table entries with higher scores */
175         while((table_ptr->score > score)&&(index < numread))
176         {
177             if(SAMEUSER(table_ptr))
178             {
179                 already = 1;
180                 break;
181             }
182             table_ptr++;
183             index++;
184         }
185        /* pass table entries with equal score but higher or equal level */
186 
187         while((table_ptr->level>=level)&&
188             (index<numread)&&
189             (table_ptr->score==score))
190         {
191             if(SAMEUSER(table_ptr))
192             {
193                 already = 1;
194                 break;
195             }
196             table_ptr++;
197             index++;
198         }
199         position = index;
200         /* if already found: done */
201        if(already == 1)
202        {
203            numread--;
204            UNLOCK;
205            return numread;
206        }
207     /* shift down score list */
208        while(index < numread)
209        {
210            /* swap *table_ptr and new_entry */
211            temp_entry = *table_ptr;
212            *table_ptr = new_entry;
213            new_entry = temp_entry;
214            if(SAMEUSER(&new_entry))
215            {
216                already = 1;
217                numread--; /* an older entry found */
218                break;
219            }
220            table_ptr++;
221            index++;
222        }
223        /* if all shifted without finding an older entry */
224        if(already==0)
225            *table_ptr = new_entry;
226        if( position <= ENTRIES )
227            printf("You rank %d in the hiscore table.\n",position);
228        else
229            printf("Sorry, you didnt make it into the hiscore table this time.\n");
230     }
231     else
232     {
233         printf("\nCreating new hiscore table.\n\n");
234         *table_ptr = new_entry;
235         numread++;
236     }
237     numread = ( (numread > ENTRIES) ? ENTRIES : numread );
238 
239     if((fp = fopen(HISCOREPATH,W_BIN)) != NULL)
240     {
241         table_ptr = table;
242         numsaved = fwrite(VOIDSTAR table_ptr, sizeof(score_entry), numread, fp);
243         chmod(HISCOREPATH,0666);
244         if(numsaved < numread)
245         {
246             printf("ERROR! Only %d items saved from %d !\n",numsaved,numread);
247             output_value = 0;
248         }
249         fclose(fp);
250     }
251     else
252         err(1,"%s","Error in savescore - fopen HISCOREPATH failed\n");
253 
254     UNLOCK;
255     return output_value;
256 }
257 
258 /**/
259 /*************************
260 *      delete_entry      *
261 **************************/
delete_entry(int num)262 void delete_entry(int num)
263 {
264     score_entry table[ENTRIES + 22],
265                   *table_ptr = table,
266                 new_entry,temp_entry;
267     int  numread,index = 1, numsaved, lock, output_value = 1;
268     FILE *fp;
269 
270     LOCK;
271     numread = readtable(table_ptr);
272     if (numread == 0) {
273         printf("Missing or unreadable hiscore table.\n\n");
274         UNLOCK;
275         exit(1);
276     }
277     if (num > numread) {
278         printf("Invalid entry, choose again\n");
279         UNLOCK;
280         return;
281     }
282     while(index < num)
283     {
284         index++;
285         table_ptr++;
286     }
287     while(index < numread)
288     {
289         index++;
290         *table_ptr = *(table_ptr+1);
291         table_ptr++;
292     }
293     numread--;
294 
295     if((fp = fopen(HISCOREPATH,W_BIN)) != NULL)
296     {
297         table_ptr = table;
298         numsaved = fwrite(VOIDSTAR table_ptr, sizeof(score_entry), numread, fp);
299         chmod(HISCOREPATH,0666);
300         if(numsaved < numread)
301         {
302             printf("ERROR! Only %d items saved from %d !\n",numsaved,numread);
303             output_value = 0;
304         }
305         fclose(fp);
306     }
307     else
308         err(1, "%s", "Could not open Scorefile\n");
309     UNLOCK;
310     show_scores(table,numsaved);
311 }
312 
313 /**/
314 /************************
315 *      erase_scores     *
316 *************************/
erase_scores()317 erase_scores()
318 {
319     int erasenum;
320     int numread;
321     int index = 0;
322     char correct[20], c;
323     score_entry table[ENTRIES + 2], *table_ptr = table;
324 
325     printf("Please enter password:");
326     while((c = getchar()) != '\n' && index <19)
327     {
328         correct[index++] = c;
329     }
330     correct[index] = 0;
331     if(strcmp(correct,MASTERPASSWORD))
332     {
333         printf("\nFoo, charlatan!\n");
334         return 0;
335     }
336     numread = readtable(table_ptr);
337     show_scores(table,numread);
338     printf("\n");
339 
340     for(;;)
341     {
342         printf("Number to erase (0 to exit): ");
343         scanf("%d",&erasenum);
344         printf("\n");
345         if(erasenum == 0)
346             break;
347         delete_entry(erasenum);
348         printf("\n");
349     }
350     printf("Byee!\n");
351 }
352