-
Notifications
You must be signed in to change notification settings - Fork 7
/
hiscore.c
286 lines (236 loc) · 7.36 KB
/
hiscore.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/*
* IceBreaker
* Copyright (c) 2000-2020 Matthew Miller <[email protected]> and
* Enrico Tassi <[email protected]>
*
* <http://www.mattdm.org/icebreaker/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include "icebreaker.h"
#include "globals.h"
#include "hiscore.h"
#include "lock.h"
char hiscorename[HISCORENUM][50];
long hiscoreval[HISCORENUM];
static char temphiscorename[HISCORENUM+1][50]; //used for sorting
static long temphiscoreval[HISCORENUM+1];
// used if we can't get write access to the high score file immediately
static char delayedhiscorename[HISCORENUM+1][50];
static long delayedhiscoreval[HISCORENUM+1];
static int cmpscore(int * a, int * b);
static void sorthiscore(char hiname[HISCORENUM][50],long hival[HISCORENUM],char * username, long score);
static void writehiscores(char * username, long thisgamescore);
static void adddelayedhiscore(char* username,long finalscore);
void inithiscores()
{
int i;
readhiscores();
// zero out the just-in-case array
for (i=0;i<HISCORENUM;i++)
{
delayedhiscoreval[i]=0;
}
}
void readhiscores()
{
FILE *hiscorefile;
char linebuf[80];
char filename[274]; // fix -- use defined OS constant
int arrayindex[HISCORENUM];
int i;
// fill the "helper" array.
for (i=0;i<HISCORENUM;i++)
arrayindex[i]=i;
// make sure all entries are zeroed out to start.
for (i=0;i<HISCORENUM;i++)
{
snprintf(temphiscorename[i],7,"Nobody");
temphiscoreval[i]=100; //100 is better than 0. :)
}
snprintf(filename,274,"%s/%s",homedir,HISCOREFILE);
hiscorefile=fopen(filename,"r");
if (hiscorefile==NULL)
{
// It's writing we need to worry about, really, so don't
// complain here.
//fprintf(stderr,"Can't read high score file; continuing anyway.\nYou may want to ask your sysadmin to make sure this program can access\n " homedir "/" HISCOREFILE "\n");
}
else
{
for (i=0;i<HISCORENUM;i++)
{
if (fgets(linebuf,80,hiscorefile))
{
sscanf(linebuf,"%49s %30ld",temphiscorename[i],&temphiscoreval[i]);
}
}
fclose(hiscorefile);
// sort arrayindex based on the corresponding hiscoreval
// really, the array should already be sorted. but you never know.
qsort(arrayindex, HISCORENUM, sizeof(int), (int (*)(const void*,const void*))cmpscore);
}
// ok, so now, we can copy things over in the proper sorted order
for (i=0;i<HISCORENUM;i++)
{
snprintf(hiscorename[i],50,"%s",temphiscorename[arrayindex[i]]);
hiscoreval[i]=temphiscoreval[arrayindex[i]];
}
}
int checkhiscore(long thisgamescore)
{
// need to re-read from disk in case another user has obtained
// a better score in the meantime...
readhiscores();
// check to see if score is better than the lowest high score
return (thisgamescore>hiscoreval[HISCORENUM-1]);
}
int addhiscore(char* username, long finalscore, int candelay)
{
int gotlock=false;
int rc=-1;
FILE_DESC filelock;
char filename[274]; // fix -- use defined OS constant
snprintf(filename,274,"%s/%s",homedir,HISCORELOCKFILE);
filelock = openlockfile(filename);
if (filelock == INVALID_FILE_DESC)
{
fprintf(stderr,"Can't access lock file -- this means we can't save the high scores.\n"
"You may want to ask your sysadmin to make sure this program can write to\n"
"<%s>.\n",filename);
}
else
{
gotlock = lock(filelock);
if (!gotlock)
{
if (checkhiscore(finalscore))
writehiscores(username,finalscore);
else
rc=0;
gotlock=unlock(filelock);
if (gotlock)
{
fprintf(stderr,"Warning: something very strange has happened. This isn't good.\n"
"Can't unlock <%s>!\n",filename);
}
}
else if (candelay)
{
adddelayedhiscore(username,finalscore);
}
else
{
fprintf(stderr,"Someone is holding onto the lock file and we can't save high scores, so\n"
"despite our best efforts, %s's high score of %ld was dropped.\n",username,finalscore);
}
closelockfile(filelock);
}
return rc;
}
void writedelayedhiscores()
{
int i;
for (i=0;i<HISCORENUM;i++)
{
if(delayedhiscoreval[i]!=0) // fix -- we're done if this happens, right?
{
if(!addhiscore(delayedhiscorename[i],delayedhiscoreval[i],false))
{
// I think it's let better to let people figure this
// out by themselves than to clutter up stderr -- they
// can just compare and see that the score was beaten.
//fprintf(stderr,"Sorry: %s %ld was a high score once, but now it's been beaten.\n",delayedhiscorename[i],delayedhiscoreval[i]);
}
else
{
// pointless at the end of the game, but needed if this function
// were to be called midgame.
delayedhiscoreval[i]=0;
}
}
}
}
void sorthiscore(char hiname[HISCORENUM][50],long hival[HISCORENUM],char * username, long score)
{
int arrayindex[HISCORENUM+1]; // note the +1 -- we're including the new score
int i;
// make sure the temp array contains the right data
for (i=0;i<HISCORENUM;i++)
{
snprintf(temphiscorename[i],50,"%s",hiname[i]);
temphiscoreval[i]=hival[i];
}
// and toss in the new data
//(this is why these arrays are size HISCORENUM+1)
snprintf(temphiscorename[HISCORENUM],50,"%s",username);
temphiscoreval[HISCORENUM]=score;
// fill the "helper" array.
for (i=0;i<HISCORENUM+1;i++)
arrayindex[i]=i;
// ok, now sort those
qsort(arrayindex, HISCORENUM+1, sizeof(int), (int (*)(const void*,const void*))cmpscore);
// and take the top ones back.
for (i=0;i<HISCORENUM;i++)
{
snprintf(hiname[i],50,"%s",temphiscorename[arrayindex[i]]);
hival[i]=temphiscoreval[arrayindex[i]];
}
}
void writehiscores(char * username, long thisgamescore)
{
FILE *hiscorefile;
char filename[274]; // fix -- use defined OS constant
int i;
sorthiscore(hiscorename,hiscoreval,username,thisgamescore);
snprintf(filename,274,"%s/%s",homedir,HISCOREFILE);
hiscorefile=fopen(filename,"w");
if (hiscorefile==NULL)
{
fprintf(stderr,"Can't save high scores."
"You may want to ask your sysadmin to make sure this program can write to\n"
"<%s>.\n",filename);
}
else
{
// FIX -- make this go so people can have spaces in their names
//for (i=0;hiscorename[i]!='\0';i++)
// if (hiscorename[i]==' ') hiscorename[i]='_';
for (i=0;i<HISCORENUM;i++)
{
fprintf(hiscorefile,"%s %ld\n",hiscorename[i],hiscoreval[i]);
}
fclose(hiscorefile);
}
}
void adddelayedhiscore(char* username,long finalscore)
{
// int i;
sorthiscore(delayedhiscorename,delayedhiscoreval,username,finalscore);
//Uncomment for debugging
/*for (i=0;i<HISCORENUM;i++)
{
if(delayedhiscoreval[i] != 0)
printf("%2d : %s %ld\n",i,delayedhiscorename[i],delayedhiscoreval[i]);
} */
}
int cmpscore(int * a, int * b)
{
return(temphiscoreval[*b] - temphiscoreval[*a]);
}