ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/hiscore.c
Revision: 1.2
Committed: Sun Aug 13 17:16:04 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +1 -1 lines
State: FILE REMOVED
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

# Content
1 /*
2 * static char *rcsid_hiscore_c =
3 * "$Id$";
4 */
5
6 /*
7 CrossFire, A Multiplayer game for X-windows
8
9 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26 The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28
29 #include <global.h>
30 #ifndef __CEXTRACT__
31 #include <sproto.h>
32 #endif
33
34 /*
35 * The score structure is used when treating new high-scores
36 */
37
38 typedef struct scr {
39 char name[BIG_NAME]; /* name */
40 char title[BIG_NAME]; /* Title */
41 char killer[BIG_NAME]; /* name (+ title) or "quit" */
42 sint64 exp; /* Experience */
43 char maplevel[BIG_NAME]; /* Killed on what level */
44 int maxhp,maxsp,maxgrace; /* Max hp, sp, grace when killed */
45 int position; /* Position in the highscore list */
46 } score;
47
48 /*
49 * spool works mostly like strtok(char *, ":"), but it can also
50 * log a specified error message if something goes wrong.
51 */
52
53 char *spool(char *bp,char *error) {
54 static char *prev_pos = NULL;
55 char *next_pos;
56 if (bp == NULL) {
57 if (prev_pos == NULL) {
58 LOG(llevError, "Called spool (%s) with NULL without previous call.\n",
59 error);
60 return NULL;
61 }
62 bp = prev_pos;
63 }
64 if (*bp == '\0') {
65 LOG(llevError, "spool: End of line at %s\n", error);
66 return NULL;
67 }
68 if ((next_pos = strchr(bp, ':')) != NULL) {
69 *next_pos = '\0';
70 prev_pos = next_pos + 1;
71 } else
72 prev_pos = NULL;
73 return bp;
74 }
75
76 /*
77 * Does what it says, copies the contents of the first score structure
78 * to the second one.
79 */
80
81 static void copy_score(score *sc1,score *sc2) {
82 strncpy(sc2->name, sc1->name, BIG_NAME);
83 sc2->name[BIG_NAME - 1] = '\0';
84 strncpy(sc2->title, sc1->title, BIG_NAME);
85 sc2->title[BIG_NAME - 1] = '\0';
86 strncpy(sc2->killer, sc1->killer, BIG_NAME);
87 sc2->killer[BIG_NAME - 1] = '\0';
88 sc2->exp = sc1->exp;
89 strcpy(sc2->maplevel,sc1->maplevel);
90 sc2->maxhp = sc1->maxhp;
91 sc2->maxsp = sc1->maxsp;
92 sc2->maxgrace = sc1->maxgrace;
93 }
94
95 /*
96 * Writes the given score structure to a static buffer, and returns
97 * a pointer to it.
98 */
99
100 static char *put_score(score *sc) {
101 static char buf[MAX_BUF];
102 #ifndef WIN32
103 sprintf(buf,"%s:%s:%lld:%s:%s:%d:%d:%d",sc->name,sc->title,sc->exp,sc->killer,sc->maplevel,
104 sc->maxhp,sc->maxsp,sc->maxgrace);
105 #else
106 sprintf(buf,"%s:%s:%I64d:%s:%s:%d:%d:%d",sc->name,sc->title,sc->exp,sc->killer,sc->maplevel,
107 sc->maxhp,sc->maxsp,sc->maxgrace);
108 #endif
109 return buf;
110 }
111
112 /*
113 * The oposite of put_score, get_score reads from the given buffer into
114 * a static score structure, and returns a pointer to it.
115 */
116
117 static score *get_score(char *bp) {
118 static score sc;
119 char *cp;
120
121 if((cp=strchr(bp,'\n'))!=NULL)
122 *cp='\0';
123
124 if ((cp = spool(bp, "name")) == NULL)
125 return NULL;
126 strncpy(sc.name,cp,BIG_NAME);
127 sc.name[BIG_NAME - 1] = '\0';
128
129 if ((cp = spool(NULL, "title")) == NULL)
130 return NULL;
131 strncpy(sc.title,cp,BIG_NAME);
132 sc.title[BIG_NAME - 1] = '\0';
133
134 if ((cp = spool(NULL, "score")) == NULL)
135 return NULL;
136 #ifndef WIN32
137 sscanf(cp,"%lld",&sc.exp);
138 #else
139 sscanf(cp,"%I64d",&sc.exp);
140 #endif
141
142 if ((cp = spool(NULL, "killer")) == NULL)
143 return NULL;
144 strncpy(sc.killer, cp, BIG_NAME);
145 sc.killer[BIG_NAME - 1] = '\0';
146
147 if ((cp = spool(NULL, "map")) == NULL)
148 return NULL;
149 strncpy(sc.maplevel, cp, BIG_NAME);
150 sc.maplevel[BIG_NAME - 1] = '\0';
151
152 if ((cp = spool(NULL, "maxhp")) == NULL)
153 return NULL;
154 sscanf(cp, "%d", &sc.maxhp);
155
156 if ((cp = spool(NULL, "maxsp")) == NULL)
157 return NULL;
158 sscanf(cp, "%d", &sc.maxsp);
159
160 if ((cp = spool(NULL, "maxgrace")) == NULL)
161 return NULL;
162 sscanf(cp, "%d", &sc.maxgrace);
163 return &sc;
164 }
165
166 static char * draw_one_high_score(score *sc) {
167 static char retbuf[MAX_BUF];
168
169 if(!strncmp(sc->killer,"quit",MAX_NAME))
170 sprintf(retbuf,"%3d %10lld %s the %s quit the game on map %s [%d][%d][%d].",
171 sc->position,sc->exp,sc->name,sc->title,sc->maplevel,sc->maxhp,sc->maxsp,
172 sc->maxgrace);
173 else if(!strncmp(sc->killer,"left",MAX_NAME))
174 sprintf(retbuf,"%3d %10lld %s the %s left the game on map %s [%d][%d][%d].",
175 sc->position,sc->exp,sc->name,sc->title,sc->maplevel,sc->maxhp,sc->maxsp,
176 sc->maxgrace);
177 else
178 sprintf(retbuf,"%3d %10lld %s the %s was killed by %s on map %s [%d][%d][%d].",
179 sc->position,sc->exp,sc->name,sc->title,sc->killer,sc->maplevel,
180 sc->maxhp,sc->maxsp,sc->maxgrace);
181 return retbuf;
182 }
183 /*
184 * add_score() adds the given score-structure to the high-score list, but
185 * only if it was good enough to deserve a place.
186 */
187
188 static score *add_score(score *new_score) {
189 FILE *fp;
190 static score old_score;
191 score *tmp_score,pscore[HIGHSCORE_LENGTH];
192 char buf[MAX_BUF], filename[MAX_BUF], *bp;
193 int nrofscores=0,flag=0,i,comp;
194
195 new_score->position=HIGHSCORE_LENGTH+1;
196 old_score.position= -1;
197 sprintf(filename,"%s/%s",settings.localdir,HIGHSCORE);
198 if((fp=open_and_uncompress(filename,1,&comp))!=NULL) {
199 while(fgets(buf,MAX_BUF,fp)!=NULL&&nrofscores<HIGHSCORE_LENGTH) {
200 if((tmp_score=get_score(buf))==NULL) break;
201 if(!flag&&new_score->exp>=tmp_score->exp) {
202 copy_score(new_score,&pscore[nrofscores]);
203 new_score->position=nrofscores;
204 flag=1;
205 if(++nrofscores>=HIGHSCORE_LENGTH)
206 break;
207 }
208 if(!strcmp(new_score->name,tmp_score->name)) { /* Another entry */
209 copy_score(tmp_score,&old_score);
210 old_score.position=nrofscores;
211 if(flag)
212 continue;
213 }
214 copy_score(tmp_score,&pscore[nrofscores++]);
215 }
216 close_and_delete(fp, comp);
217 }
218 if(old_score.position!=-1&&old_score.exp>=new_score->exp)
219 return &old_score; /* Did not beat old score */
220 if(!flag&&nrofscores<HIGHSCORE_LENGTH)
221 copy_score(new_score,&pscore[nrofscores++]);
222 if((fp=fopen(filename,"w"))==NULL) {
223 LOG(llevError, "Cannot write to highscore file %s: %s\n", filename, strerror_local(errno));
224 return NULL;
225 }
226 for(i=0;i<nrofscores;i++) {
227 bp=put_score(&pscore[i]);
228 fprintf(fp,"%s\n",bp);
229 }
230 fclose(fp);
231 if(flag) {
232 /* Eneq(@csd.uu.se): Patch to fix error in adding a new score to the
233 hiscore-list */
234 if(old_score.position==-1)
235 return new_score;
236 return &old_score;
237 }
238 new_score->position= -1;
239 if(old_score.position!=-1)
240 return &old_score;
241 if(nrofscores) {
242 copy_score(&pscore[nrofscores-1],&old_score);
243 return &old_score;
244 }
245 LOG(llevError,"Highscore error.\n");
246 return NULL;
247 }
248
249 void check_score(object *op) {
250 score new_score;
251 score *old_score;
252
253 if(op->stats.exp==0)
254 return;
255
256 if(!op->contr->name_changed) {
257 if(op->stats.exp>0) {
258 new_draw_info(NDI_UNIQUE, 0,op,"As you haven't changed your name, you won't");
259 new_draw_info(NDI_UNIQUE, 0,op,"get into the high-score list.");
260 }
261 return;
262 }
263 if(QUERY_FLAG(op,FLAG_WAS_WIZ)) {
264 new_draw_info(NDI_UNIQUE, 0,op,"Since you have been in wizard mode,");
265 new_draw_info(NDI_UNIQUE, 0,op,"you can't enter the high-score list.");
266 return;
267 }
268 if (op->contr->explore) {
269 new_draw_info(NDI_UNIQUE, 0,op,"Since you were in explore mode,");
270 new_draw_info(NDI_UNIQUE, 0,op,"you can't enter the high-score list.");
271 return;
272 }
273 strncpy(new_score.name,op->name,BIG_NAME);
274 new_score.name[BIG_NAME-1] = '\0';
275 strncpy(new_score.title,op->contr->own_title,BIG_NAME);
276 if(new_score.title[0]=='\0')
277 strncpy(new_score.title,op->contr->title,BIG_NAME);
278 new_score.title[BIG_NAME-1] = '\0';
279 strncpy(new_score.killer,op->contr->killer,BIG_NAME);
280 if(new_score.killer[0]=='\0')
281 strcpy(new_score.killer,"a dungeon collapse");
282 new_score.killer[BIG_NAME-1] = '\0';
283 new_score.exp=op->stats.exp;
284 if(op->map == NULL)
285 *new_score.maplevel = '\0';
286 else {
287 strncpy(new_score.maplevel,
288 op->map->name?op->map->name:op->map->path,
289 BIG_NAME-1);
290 new_score.maplevel[BIG_NAME-1] = '\0';
291 }
292 new_score.maxhp=(int) op->stats.maxhp;
293 new_score.maxsp=(int) op->stats.maxsp;
294 new_score.maxgrace=(int) op->stats.maxgrace;
295 if((old_score=add_score(&new_score))==NULL) {
296 new_draw_info(NDI_UNIQUE, 0,op,"Error in the highscore list.");
297 return;
298 }
299 if(new_score.position == -1) {
300 new_score.position = HIGHSCORE_LENGTH+1; /* Not strictly correct... */
301 if(!strcmp(old_score->name,new_score.name))
302 new_draw_info(NDI_UNIQUE, 0,op,"You didn't beat your last highscore:");
303 else
304 new_draw_info(NDI_UNIQUE, 0,op,"You didn't enter the highscore list:");
305 new_draw_info(NDI_UNIQUE, 0,op, draw_one_high_score(old_score));
306 new_draw_info(NDI_UNIQUE, 0,op, draw_one_high_score(&new_score));
307 return;
308 }
309 if(old_score->exp>=new_score.exp)
310 new_draw_info(NDI_UNIQUE, 0,op,"You didn't beat your last score:");
311 else
312 new_draw_info(NDI_UNIQUE, 0,op,"You beat your last score:");
313
314 new_draw_info(NDI_UNIQUE, 0,op, draw_one_high_score(old_score));
315 new_draw_info(NDI_UNIQUE, 0,op, draw_one_high_score(&new_score));
316 }
317
318
319
320 /* displays the high score file. object is the calling object
321 * (null if being called via command line.) max is the maximum
322 * number of scores to display. match, if set, is the name or class
323 * to match to.
324 */
325
326 void display_high_score(object *op,int max, const char *match) {
327 const size_t maxchar = 80;
328 FILE *fp;
329 char buf[MAX_BUF],*scorebuf, *bp, *cp;
330 int i=0,j=0,comp;
331 score *sc;
332
333 sprintf(buf,"%s/%s",settings.localdir,HIGHSCORE);
334 if((fp=open_and_uncompress(buf,0,&comp))==NULL) {
335 LOG(llevError, "Cannot open highscore file %s: %s\n", buf, strerror_local(errno));
336 if(op!=NULL)
337 new_draw_info(NDI_UNIQUE, 0,op,"There is no highscore file.");
338 return;
339 }
340 if(op != NULL)
341 clear_win_info(op);
342 new_draw_info(NDI_UNIQUE, 0,op,"Nr Score Who [max hp][max sp][max grace]");
343
344 while(fgets(buf,MAX_BUF,fp)!=NULL) {
345 if(j>=HIGHSCORE_LENGTH||i>=(max-1))
346 break;
347 if((sc=get_score(buf))==NULL)
348 break;
349 sc->position=++j;
350 if (match==NULL) {
351 scorebuf=draw_one_high_score(sc);
352 i++;
353 } else {
354 if (!strcasecmp(sc->name, match) || !strcasecmp(sc->title, match)) {
355 scorebuf=draw_one_high_score(sc);
356 i++;
357 }
358 else continue;
359 }
360 /* Replaced what seemed to an overly complicated word wrap method
361 * still word wraps, but assumes at most 2 lines of data.
362 * mw - 2-12-97
363 */
364 strncpy(buf,scorebuf,MAX_BUF);
365 buf[MAX_BUF-1] = '\0';
366 cp=buf;
367 while (strlen(cp)> maxchar) {
368 bp = cp+maxchar-1;
369 while (*bp != ' ' && bp>cp) bp--;
370 *bp='\0';
371 if (op == NULL) {
372 LOG(llevDebug, "%s\n", cp);
373 }
374 else {
375 new_draw_info(NDI_UNIQUE, 0,op,cp);
376 }
377 sprintf(buf, " %s", bp+1);
378 cp = buf;
379 i++;
380 }
381 if(op == NULL)
382 LOG(llevDebug, "%s\n", buf);
383 else
384 new_draw_info(NDI_UNIQUE, 0,op,buf);
385 }
386 close_and_delete(fp, comp);
387 }