ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/hiscore.C
Revision: 1.3
Committed: Wed Aug 30 16:30:37 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +3 -3 lines
Log Message:
remove compression support, intiialise perl earlier etc. etc.

File Contents

# User Rev Content
1 elmex 1.1 /*
2     * static char *rcsid_hiscore_c =
3 root 1.3 * "$Id: hiscore.C,v 1.2 2006-08-29 08:01:37 root Exp $";
4 elmex 1.1 */
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 root 1.2 sprintf(retbuf,"%3d %10lld %s the %s quit the game on map %s [%d][%d][%d].",
171 elmex 1.1 sc->position,sc->exp,sc->name,sc->title,sc->maplevel,sc->maxhp,sc->maxsp,
172 root 1.2 sc->maxgrace);
173 elmex 1.1 else if(!strncmp(sc->killer,"left",MAX_NAME))
174 root 1.2 sprintf(retbuf,"%3d %10lld %s the %s left the game on map %s [%d][%d][%d].",
175 elmex 1.1 sc->position,sc->exp,sc->name,sc->title,sc->maplevel,sc->maxhp,sc->maxsp,
176 root 1.2 sc->maxgrace);
177 elmex 1.1 else
178 root 1.2 sprintf(retbuf,"%3d %10lld %s the %s was killed by %s on map %s [%d][%d][%d].",
179 elmex 1.1 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 root 1.3 LOG(llevError, "Cannot write to highscore file %s: %s\n", filename, strerror(errno));
224 elmex 1.1 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 root 1.2 return;
255 elmex 1.1
256     if(!op->contr->name_changed) {
257 root 1.2 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 elmex 1.1 }
263     if(QUERY_FLAG(op,FLAG_WAS_WIZ)) {
264 root 1.2 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 elmex 1.1 }
268     if (op->contr->explore) {
269 root 1.2 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 elmex 1.1 }
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 root 1.2 strncpy(new_score.title,op->contr->title,BIG_NAME);
278 elmex 1.1 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 root 1.2 strcpy(new_score.killer,"a dungeon collapse");
282 elmex 1.1 new_score.killer[BIG_NAME-1] = '\0';
283     new_score.exp=op->stats.exp;
284     if(op->map == NULL)
285 root 1.2 *new_score.maplevel = '\0';
286 elmex 1.1 else {
287 root 1.2 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 elmex 1.1 }
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 root 1.2 new_draw_info(NDI_UNIQUE, 0,op,"Error in the highscore list.");
297     return;
298 elmex 1.1 }
299     if(new_score.position == -1) {
300 root 1.2 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 elmex 1.1 }
309     if(old_score->exp>=new_score.exp)
310 root 1.2 new_draw_info(NDI_UNIQUE, 0,op,"You didn't beat your last score:");
311 elmex 1.1 else
312 root 1.2 new_draw_info(NDI_UNIQUE, 0,op,"You beat your last score:");
313 elmex 1.1
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 root 1.3 LOG(llevError, "Cannot open highscore file %s: %s\n", buf, strerror(errno));
336 root 1.2 if(op!=NULL)
337     new_draw_info(NDI_UNIQUE, 0,op,"There is no highscore file.");
338     return;
339 elmex 1.1 }
340     if(op != NULL)
341 root 1.2 clear_win_info(op);
342 elmex 1.1 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 root 1.2 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 elmex 1.1 }
386     close_and_delete(fp, comp);
387     }