ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/hiscore.C
Revision: 1.4
Committed: Sun Sep 3 00:18:42 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +7 -15 lines
Log Message:
THIS CODE WILL NOT COMPILE
use the STABLE tag instead.

- major changes in object lifetime and memory management
- replaced manual refcounting by shstr class
- removed quest system
- many optimisations
- major changes

File Contents

# Content
1 /*
2 * static char *rcsid_hiscore_c =
3 * "$Id: hiscore.C,v 1.3 2006-08-30 16:30:37 root Exp $";
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 sprintf(buf,"%s:%s:%lld:%s:%s:%d:%d:%d",sc->name,sc->title, (long long)sc->exp,sc->killer,sc->maplevel,
103 sc->maxhp,sc->maxsp,sc->maxgrace);
104 return buf;
105 }
106
107 /*
108 * The oposite of put_score, get_score reads from the given buffer into
109 * a static score structure, and returns a pointer to it.
110 */
111
112 static score *get_score(char *bp) {
113 static score sc;
114 char *cp;
115
116 if((cp=strchr(bp,'\n'))!=NULL)
117 *cp='\0';
118
119 if ((cp = spool(bp, "name")) == NULL)
120 return NULL;
121 strncpy(sc.name,cp,BIG_NAME);
122 sc.name[BIG_NAME - 1] = '\0';
123
124 if ((cp = spool(NULL, "title")) == NULL)
125 return NULL;
126 strncpy(sc.title,cp,BIG_NAME);
127 sc.title[BIG_NAME - 1] = '\0';
128
129 if ((cp = spool(NULL, "score")) == NULL)
130 return NULL;
131 long long exp;
132 sscanf(cp,"%lld", &exp); sc.exp = exp;
133
134 if ((cp = spool(NULL, "killer")) == NULL)
135 return NULL;
136 strncpy(sc.killer, cp, BIG_NAME);
137 sc.killer[BIG_NAME - 1] = '\0';
138
139 if ((cp = spool(NULL, "map")) == NULL)
140 return NULL;
141 strncpy(sc.maplevel, cp, BIG_NAME);
142 sc.maplevel[BIG_NAME - 1] = '\0';
143
144 if ((cp = spool(NULL, "maxhp")) == NULL)
145 return NULL;
146 sscanf(cp, "%d", &sc.maxhp);
147
148 if ((cp = spool(NULL, "maxsp")) == NULL)
149 return NULL;
150 sscanf(cp, "%d", &sc.maxsp);
151
152 if ((cp = spool(NULL, "maxgrace")) == NULL)
153 return NULL;
154 sscanf(cp, "%d", &sc.maxgrace);
155 return &sc;
156 }
157
158 static char * draw_one_high_score(score *sc) {
159 static char retbuf[MAX_BUF];
160
161 if(!strncmp(sc->killer,"quit",MAX_NAME))
162 sprintf(retbuf,"%3d %10lld %s the %s quit the game on map %s [%d][%d][%d].",
163 sc->position, (long long)sc->exp,sc->name,sc->title,sc->maplevel,sc->maxhp,sc->maxsp,
164 sc->maxgrace);
165 else if(!strncmp(sc->killer,"left",MAX_NAME))
166 sprintf(retbuf,"%3d %10lld %s the %s left the game on map %s [%d][%d][%d].",
167 sc->position, (long long)sc->exp,sc->name,sc->title,sc->maplevel,sc->maxhp,sc->maxsp,
168 sc->maxgrace);
169 else
170 sprintf(retbuf,"%3d %10lld %s the %s was killed by %s on map %s [%d][%d][%d].",
171 sc->position, (long long)sc->exp,sc->name,sc->title,sc->killer,sc->maplevel,
172 sc->maxhp,sc->maxsp,sc->maxgrace);
173 return retbuf;
174 }
175 /*
176 * add_score() adds the given score-structure to the high-score list, but
177 * only if it was good enough to deserve a place.
178 */
179
180 static score *add_score(score *new_score) {
181 FILE *fp;
182 static score old_score;
183 score *tmp_score,pscore[HIGHSCORE_LENGTH];
184 char buf[MAX_BUF], filename[MAX_BUF], *bp;
185 int nrofscores=0,flag=0,i,comp;
186
187 new_score->position=HIGHSCORE_LENGTH+1;
188 old_score.position= -1;
189 sprintf(filename,"%s/%s",settings.localdir,HIGHSCORE);
190 if((fp=open_and_uncompress(filename,1,&comp))!=NULL) {
191 while(fgets(buf,MAX_BUF,fp)!=NULL&&nrofscores<HIGHSCORE_LENGTH) {
192 if((tmp_score=get_score(buf))==NULL) break;
193 if(!flag&&new_score->exp>=tmp_score->exp) {
194 copy_score(new_score,&pscore[nrofscores]);
195 new_score->position=nrofscores;
196 flag=1;
197 if(++nrofscores>=HIGHSCORE_LENGTH)
198 break;
199 }
200 if(!strcmp(new_score->name,tmp_score->name)) { /* Another entry */
201 copy_score(tmp_score,&old_score);
202 old_score.position=nrofscores;
203 if(flag)
204 continue;
205 }
206 copy_score(tmp_score,&pscore[nrofscores++]);
207 }
208 close_and_delete(fp, comp);
209 }
210 if(old_score.position!=-1&&old_score.exp>=new_score->exp)
211 return &old_score; /* Did not beat old score */
212 if(!flag&&nrofscores<HIGHSCORE_LENGTH)
213 copy_score(new_score,&pscore[nrofscores++]);
214 if((fp=fopen(filename,"w"))==NULL) {
215 LOG(llevError, "Cannot write to highscore file %s: %s\n", filename, strerror(errno));
216 return NULL;
217 }
218 for(i=0;i<nrofscores;i++) {
219 bp=put_score(&pscore[i]);
220 fprintf(fp,"%s\n",bp);
221 }
222 fclose(fp);
223 if(flag) {
224 /* Eneq(@csd.uu.se): Patch to fix error in adding a new score to the
225 hiscore-list */
226 if(old_score.position==-1)
227 return new_score;
228 return &old_score;
229 }
230 new_score->position= -1;
231 if(old_score.position!=-1)
232 return &old_score;
233 if(nrofscores) {
234 copy_score(&pscore[nrofscores-1],&old_score);
235 return &old_score;
236 }
237 LOG(llevError,"Highscore error.\n");
238 return NULL;
239 }
240
241 void check_score(object *op) {
242 score new_score;
243 score *old_score;
244
245 if(op->stats.exp==0)
246 return;
247
248 if(!op->contr->name_changed) {
249 if(op->stats.exp>0) {
250 new_draw_info(NDI_UNIQUE, 0,op,"As you haven't changed your name, you won't");
251 new_draw_info(NDI_UNIQUE, 0,op,"get into the high-score list.");
252 }
253 return;
254 }
255 if(QUERY_FLAG(op,FLAG_WAS_WIZ)) {
256 new_draw_info(NDI_UNIQUE, 0,op,"Since you have been in wizard mode,");
257 new_draw_info(NDI_UNIQUE, 0,op,"you can't enter the high-score list.");
258 return;
259 }
260 if (op->contr->explore) {
261 new_draw_info(NDI_UNIQUE, 0,op,"Since you were in explore mode,");
262 new_draw_info(NDI_UNIQUE, 0,op,"you can't enter the high-score list.");
263 return;
264 }
265 strncpy(new_score.name,op->name,BIG_NAME);
266 new_score.name[BIG_NAME-1] = '\0';
267 strncpy(new_score.title,op->contr->own_title,BIG_NAME);
268 if(new_score.title[0]=='\0')
269 strncpy(new_score.title,op->contr->title,BIG_NAME);
270 new_score.title[BIG_NAME-1] = '\0';
271 strncpy(new_score.killer,op->contr->killer,BIG_NAME);
272 if(new_score.killer[0]=='\0')
273 strcpy(new_score.killer,"a dungeon collapse");
274 new_score.killer[BIG_NAME-1] = '\0';
275 new_score.exp=op->stats.exp;
276 if(op->map == NULL)
277 *new_score.maplevel = '\0';
278 else {
279 strncpy(new_score.maplevel,
280 op->map->name?op->map->name:op->map->path,
281 BIG_NAME-1);
282 new_score.maplevel[BIG_NAME-1] = '\0';
283 }
284 new_score.maxhp=(int) op->stats.maxhp;
285 new_score.maxsp=(int) op->stats.maxsp;
286 new_score.maxgrace=(int) op->stats.maxgrace;
287 if((old_score=add_score(&new_score))==NULL) {
288 new_draw_info(NDI_UNIQUE, 0,op,"Error in the highscore list.");
289 return;
290 }
291 if(new_score.position == -1) {
292 new_score.position = HIGHSCORE_LENGTH+1; /* Not strictly correct... */
293 if(!strcmp(old_score->name,new_score.name))
294 new_draw_info(NDI_UNIQUE, 0,op,"You didn't beat your last highscore:");
295 else
296 new_draw_info(NDI_UNIQUE, 0,op,"You didn't enter the highscore list:");
297 new_draw_info(NDI_UNIQUE, 0,op, draw_one_high_score(old_score));
298 new_draw_info(NDI_UNIQUE, 0,op, draw_one_high_score(&new_score));
299 return;
300 }
301 if(old_score->exp>=new_score.exp)
302 new_draw_info(NDI_UNIQUE, 0,op,"You didn't beat your last score:");
303 else
304 new_draw_info(NDI_UNIQUE, 0,op,"You beat your last score:");
305
306 new_draw_info(NDI_UNIQUE, 0,op, draw_one_high_score(old_score));
307 new_draw_info(NDI_UNIQUE, 0,op, draw_one_high_score(&new_score));
308 }
309
310
311
312 /* displays the high score file. object is the calling object
313 * (null if being called via command line.) max is the maximum
314 * number of scores to display. match, if set, is the name or class
315 * to match to.
316 */
317
318 void display_high_score(object *op,int max, const char *match) {
319 const size_t maxchar = 80;
320 FILE *fp;
321 char buf[MAX_BUF],*scorebuf, *bp, *cp;
322 int i=0,j=0,comp;
323 score *sc;
324
325 sprintf(buf,"%s/%s",settings.localdir,HIGHSCORE);
326 if((fp=open_and_uncompress(buf,0,&comp))==NULL) {
327 LOG(llevError, "Cannot open highscore file %s: %s\n", buf, strerror(errno));
328 if(op!=NULL)
329 new_draw_info(NDI_UNIQUE, 0,op,"There is no highscore file.");
330 return;
331 }
332 if(op != NULL)
333 clear_win_info(op);
334 new_draw_info(NDI_UNIQUE, 0,op,"Nr Score Who [max hp][max sp][max grace]");
335
336 while(fgets(buf,MAX_BUF,fp)!=NULL) {
337 if(j>=HIGHSCORE_LENGTH||i>=(max-1))
338 break;
339 if((sc=get_score(buf))==NULL)
340 break;
341 sc->position=++j;
342 if (match==NULL) {
343 scorebuf=draw_one_high_score(sc);
344 i++;
345 } else {
346 if (!strcasecmp(sc->name, match) || !strcasecmp(sc->title, match)) {
347 scorebuf=draw_one_high_score(sc);
348 i++;
349 }
350 else continue;
351 }
352 /* Replaced what seemed to an overly complicated word wrap method
353 * still word wraps, but assumes at most 2 lines of data.
354 * mw - 2-12-97
355 */
356 strncpy(buf,scorebuf,MAX_BUF);
357 buf[MAX_BUF-1] = '\0';
358 cp=buf;
359 while (strlen(cp)> maxchar) {
360 bp = cp+maxchar-1;
361 while (*bp != ' ' && bp>cp) bp--;
362 *bp='\0';
363 if (op == NULL) {
364 LOG(llevDebug, "%s\n", cp);
365 }
366 else {
367 new_draw_info(NDI_UNIQUE, 0,op,cp);
368 }
369 sprintf(buf, " %s", bp+1);
370 cp = buf;
371 i++;
372 }
373 if(op == NULL)
374 LOG(llevDebug, "%s\n", buf);
375 else
376 new_draw_info(NDI_UNIQUE, 0,op,buf);
377 }
378 close_and_delete(fp, comp);
379 }