00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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)) {
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;
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
00263
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
00354
00355
00356
00357 if (quiet)
00358 return;
00359
00360 if (new_score.position == -1) {
00361 new_score.position = HIGHSCORE_LENGTH+1;
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 }