Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_hiscore_c = 00003 * "$Id: hiscore.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2006 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 00027 */ 00028 00034 #include <global.h> 00035 #ifndef __CEXTRACT__ 00036 #include <sproto.h> 00037 #endif 00038 00043 typedef struct scr { 00044 char name[BIG_NAME]; 00045 char title[BIG_NAME]; 00046 char killer[BIG_NAME]; 00047 sint64 exp; 00048 char maplevel[BIG_NAME]; 00049 int maxhp, maxsp, maxgrace; 00050 int position; 00051 } score; 00052 00065 static char *spool(char *bp, const char *error) { 00066 static char *prev_pos = NULL; 00067 char *next_pos; 00068 00069 if (bp == NULL) { 00070 if (prev_pos == NULL) { 00071 LOG(llevError, "Called spool (%s) with NULL without previous call.\n", error); 00072 return NULL; 00073 } 00074 bp = prev_pos; 00075 } 00076 if (*bp == '\0') { 00077 LOG(llevError, "spool: End of line at %s\n", error); 00078 return NULL; 00079 } 00080 if ((next_pos = strchr(bp, ':')) != NULL) { 00081 *next_pos = '\0'; 00082 prev_pos = next_pos+1; 00083 } else 00084 prev_pos = NULL; 00085 return bp; 00086 } 00087 00097 static void copy_score(const score *sc1, score *sc2) { 00098 strncpy(sc2->name, sc1->name, BIG_NAME); 00099 sc2->name[BIG_NAME-1] = '\0'; 00100 strncpy(sc2->title, sc1->title, BIG_NAME); 00101 sc2->title[BIG_NAME-1] = '\0'; 00102 strncpy(sc2->killer, sc1->killer, BIG_NAME); 00103 sc2->killer[BIG_NAME-1] = '\0'; 00104 sc2->exp = sc1->exp; 00105 strcpy(sc2->maplevel, sc1->maplevel); 00106 sc2->maxhp = sc1->maxhp; 00107 sc2->maxsp = sc1->maxsp; 00108 sc2->maxgrace = sc1->maxgrace; 00109 } 00110 00121 static void put_score(const score *sc, char *buf, int size) { 00122 snprintf(buf, size, "%s:%s:%"FMT64":%s:%s:%d:%d:%d", sc->name, sc->title, sc->exp, sc->killer, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace); 00123 } 00124 00136 static score *get_score(char *bp) { 00137 static score sc; 00138 char *cp; 00139 00140 if ((cp = strchr(bp, '\n')) != NULL) 00141 *cp = '\0'; 00142 00143 if ((cp = spool(bp, "name")) == NULL) 00144 return NULL; 00145 strncpy(sc.name, cp, BIG_NAME); 00146 sc.name[BIG_NAME-1] = '\0'; 00147 00148 if ((cp = spool(NULL, "title")) == NULL) 00149 return NULL; 00150 strncpy(sc.title, cp, BIG_NAME); 00151 sc.title[BIG_NAME-1] = '\0'; 00152 00153 if ((cp = spool(NULL, "score")) == NULL) 00154 return NULL; 00155 00156 sscanf(cp, "%"FMT64, &sc.exp); 00157 00158 if ((cp = spool(NULL, "killer")) == NULL) 00159 return NULL; 00160 strncpy(sc.killer, cp, BIG_NAME); 00161 sc.killer[BIG_NAME-1] = '\0'; 00162 00163 if ((cp = spool(NULL, "map")) == NULL) 00164 return NULL; 00165 strncpy(sc.maplevel, cp, BIG_NAME); 00166 sc.maplevel[BIG_NAME-1] = '\0'; 00167 00168 if ((cp = spool(NULL, "maxhp")) == NULL) 00169 return NULL; 00170 sscanf(cp, "%d", &sc.maxhp); 00171 00172 if ((cp = spool(NULL, "maxsp")) == NULL) 00173 return NULL; 00174 sscanf(cp, "%d", &sc.maxsp); 00175 00176 if ((cp = spool(NULL, "maxgrace")) == NULL) 00177 return NULL; 00178 sscanf(cp, "%d", &sc.maxgrace); 00179 return ≻ 00180 } 00181 00194 static char *draw_one_high_score(const score *sc, char *buf, int size) { 00195 if (!strncmp(sc->killer, "quit", MAX_NAME)) 00196 snprintf(buf, size, "[Fixed]%3d %10"FMT64"[Print] %s the %s quit the game on map %s <%d><%d><%d>.", 00197 sc->position, sc->exp, sc->name, sc->title, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace); 00198 else if (!strncmp(sc->killer, "left", MAX_NAME)) 00199 snprintf(buf, size, "[Fixed]%3d %10"FMT64"[Print] %s the %s left the game on map %s <%d><%d><%d>.", 00200 sc->position, sc->exp, sc->name, sc->title, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace); 00201 else 00202 snprintf(buf, size, "[Fixed]%3d %10"FMT64"[Print] %s the %s was killed by %s on map %s <%d><%d><%d>.", 00203 sc->position, sc->exp, sc->name, sc->title, sc->killer, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace); 00204 return buf; 00205 } 00206 00217 static score *add_score(score *new_score) { 00218 FILE *fp; 00219 static score old_score; 00220 score *tmp_score, pscore[HIGHSCORE_LENGTH]; 00221 char buf[MAX_BUF], filename[MAX_BUF], bp[MAX_BUF]; 00222 int nrofscores = 0, flag = 0, i, comp; 00223 00224 new_score->position = HIGHSCORE_LENGTH+1; 00225 old_score.position = -1; 00226 snprintf(filename, sizeof(filename), "%s/%s", settings.localdir, HIGHSCORE); 00227 if ((fp = open_and_uncompress(filename, 1, &comp)) != NULL) { 00228 while (fgets(buf, MAX_BUF, fp) != NULL && nrofscores < HIGHSCORE_LENGTH) { 00229 if ((tmp_score = get_score(buf)) == NULL) 00230 break; 00231 if (!flag && new_score->exp >= tmp_score->exp) { 00232 copy_score(new_score, &pscore[nrofscores]); 00233 new_score->position = nrofscores; 00234 flag = 1; 00235 if (++nrofscores >= HIGHSCORE_LENGTH) 00236 break; 00237 } 00238 if (!strcmp(new_score->name, tmp_score->name)) { /* Another entry */ 00239 copy_score(tmp_score, &old_score); 00240 old_score.position = nrofscores; 00241 if (flag) 00242 continue; 00243 } 00244 copy_score(tmp_score, &pscore[nrofscores++]); 00245 } 00246 close_and_delete(fp, comp); 00247 } 00248 if (old_score.position != -1 && old_score.exp >= new_score->exp) 00249 return &old_score; /* Did not beat old score */ 00250 if (!flag && nrofscores < HIGHSCORE_LENGTH) 00251 copy_score(new_score, &pscore[nrofscores++]); 00252 if ((fp = fopen(filename, "w")) == NULL) { 00253 LOG(llevError, "Cannot write to highscore file %s: %s\n", filename, strerror_local(errno, buf, sizeof(buf))); 00254 return NULL; 00255 } 00256 for (i = 0; i < nrofscores; i++) { 00257 put_score(&pscore[i], bp, sizeof(bp)); 00258 fprintf(fp, "%s\n", bp); 00259 } 00260 fclose(fp); 00261 if (flag) { 00262 /* Eneq(@csd.uu.se): Patch to fix error in adding a new score to the 00263 hiscore-list */ 00264 if (old_score.position == -1) 00265 return new_score; 00266 return &old_score; 00267 } 00268 new_score->position = -1; 00269 if (old_score.position != -1) 00270 return &old_score; 00271 if (nrofscores) { 00272 copy_score(&pscore[nrofscores-1], &old_score); 00273 return &old_score; 00274 } 00275 LOG(llevError, "Highscore error.\n"); 00276 return NULL; 00277 } 00278 00289 void check_score(object *op, int quiet) { 00290 score new_score; 00291 score *old_score; 00292 char bufscore[MAX_BUF]; 00293 00294 if (op->stats.exp == 0) 00295 return; 00296 00297 if (!op->contr->name_changed) { 00298 if (op->stats.exp > 0) { 00299 if (!quiet) 00300 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00301 "As you haven't changed your name, you won't " 00302 "get into the high-score list.", NULL); 00303 } 00304 return; 00305 } 00306 if (QUERY_FLAG(op, FLAG_WAS_WIZ)) { 00307 if (!quiet) 00308 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00309 "Since you have been in wizard mode, " 00310 "you can't enter the high-score list.", NULL); 00311 return; 00312 } 00313 if (op->contr->explore) { 00314 if (!quiet) 00315 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00316 "Since you were in explore mode, " 00317 "you can't enter the high-score list.", NULL); 00318 return; 00319 } 00320 if (!op->stats.exp) { 00321 if (!quiet) 00322 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR, 00323 "You don't deserve to save your character yet.", NULL); 00324 return; 00325 } 00326 00327 strncpy(new_score.name, op->name, BIG_NAME); 00328 new_score.name[BIG_NAME-1] = '\0'; 00329 strncpy(new_score.title, op->contr->own_title, BIG_NAME); 00330 if (new_score.title[0] == '\0') 00331 strncpy(new_score.title, op->contr->title, BIG_NAME); 00332 new_score.title[BIG_NAME-1] = '\0'; 00333 strncpy(new_score.killer, op->contr->killer, BIG_NAME); 00334 if (new_score.killer[0] == '\0') 00335 strcpy(new_score.killer, "a dungeon collapse"); 00336 new_score.killer[BIG_NAME-1] = '\0'; 00337 new_score.exp = op->stats.exp; 00338 if (op->map == NULL) 00339 *new_score.maplevel = '\0'; 00340 else { 00341 strncpy(new_score.maplevel, op->map->name ? op->map->name : op->map->path, BIG_NAME-1); 00342 new_score.maplevel[BIG_NAME-1] = '\0'; 00343 } 00344 new_score.maxhp = (int)op->stats.maxhp; 00345 new_score.maxsp = (int)op->stats.maxsp; 00346 new_score.maxgrace = (int)op->stats.maxgrace; 00347 if ((old_score = add_score(&new_score)) == NULL) { 00348 if (!quiet) 00349 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00350 "Error in the highscore list.", NULL); 00351 return; 00352 } 00353 /* Everything below here is just related to print messages 00354 * to the player. If quiet is set, we can just return 00355 * now. 00356 */ 00357 if (quiet) 00358 return; 00359 00360 if (new_score.position == -1) { 00361 new_score.position = HIGHSCORE_LENGTH+1; /* Not strictly correct... */ 00362 00363 if (!strcmp(old_score->name, new_score.name)) 00364 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, 00365 "You didn't beat your last highscore:", NULL); 00366 else 00367 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, 00368 "You didn't enter the highscore list:", NULL); 00369 00370 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, 00371 draw_one_high_score(old_score, bufscore, sizeof(bufscore)), NULL); 00372 00373 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, 00374 draw_one_high_score(&new_score, bufscore, sizeof(bufscore)), NULL); 00375 return; 00376 } 00377 if (old_score->exp >= new_score.exp) 00378 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, 00379 "You didn't beat your last score:", NULL); 00380 else 00381 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, 00382 "You beat your last score:", NULL); 00383 00384 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, 00385 draw_one_high_score(old_score, bufscore, sizeof(bufscore)), NULL); 00386 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, 00387 draw_one_high_score(&new_score, bufscore, sizeof(bufscore)), NULL); 00388 } 00389 00390 00391 00402 void display_high_score(object *op, int max, const char *match) { 00403 FILE *fp; 00404 char buf[MAX_BUF], scorebuf[MAX_BUF]; 00405 int i = 0, j = 0, comp; 00406 score *sc; 00407 00408 snprintf(buf, sizeof(buf), "%s/%s", settings.localdir, HIGHSCORE); 00409 if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL) { 00410 char err[MAX_BUF]; 00411 00412 LOG(llevError, "Cannot open highscore file %s: %s\n", buf, strerror_local(errno, err, sizeof(err))); 00413 if (op != NULL) 00414 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00415 "There is no highscore file.", NULL); 00416 return; 00417 } 00418 00419 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, 00420 "[Fixed]Nr Score Who <max hp><max sp><max grace>", 00421 "Nr Score Who <max hp><max sp><max grace>"); 00422 00423 while (fgets(buf, MAX_BUF, fp) != NULL) { 00424 if (j >= HIGHSCORE_LENGTH || i >= (max-1)) 00425 break; 00426 if ((sc = get_score(buf)) == NULL) 00427 break; 00428 sc->position = ++j; 00429 if (match == NULL 00430 || strcasestr_local(sc->name, match) 00431 || strcasestr_local(sc->title, match)) { 00432 draw_one_high_score(sc, scorebuf, sizeof(scorebuf)); 00433 i++; 00434 } else 00435 continue; 00436 00437 if (op == NULL) 00438 LOG(llevDebug, "%s\n", scorebuf); 00439 else 00440 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_HISCORE, scorebuf, NULL); 00441 00442 } 00443 close_and_delete(fp, comp); 00444 }