| 1 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ |
| 2 | /* hack.end.c - version 1.0.3 */ |
| 3 | /* $FreeBSD: src/games/hack/hack.end.c,v 1.4 1999/11/16 10:26:36 marcel Exp $ */ |
| 4 | |
| 5 | #include "hack.h" |
| 6 | #define Sprintf (void) sprintf |
| 7 | |
| 8 | #define newttentry() alloc(sizeof(struct toptenentry)) |
| 9 | #define NAMSZ 8 |
| 10 | #define DTHSZ 40 |
| 11 | #define PERSMAX 1 |
| 12 | #define POINTSMIN 1 /* must be > 0 */ |
| 13 | #define ENTRYMAX 100 /* must be >= 10 */ |
| 14 | #define PERS_IS_UID /* delete for PERSMAX per name; now per uid */ |
| 15 | struct toptenentry { |
| 16 | struct toptenentry *tt_next; |
| 17 | long int points; |
| 18 | int level,maxlvl,hp,maxhp; |
| 19 | int uid; |
| 20 | char plchar; |
| 21 | char sex; |
| 22 | char name[NAMSZ+1]; |
| 23 | char death[DTHSZ+1]; |
| 24 | char date[7]; /* yymmdd */ |
| 25 | } *tt_head; |
| 26 | |
| 27 | static void done_intr(int); |
| 28 | static void done_hangup(int); |
| 29 | static void topten(void); |
| 30 | static void outheader(void); |
| 31 | static int outentry(int, struct toptenentry *, int); |
| 32 | static char *itoa(int); |
| 33 | static const char *ordin(int); |
| 34 | |
| 35 | xchar maxdlevel = 1; |
| 36 | |
| 37 | void |
| 38 | done1(int unused __unused) |
| 39 | { |
| 40 | signal(SIGINT, SIG_IGN); |
| 41 | pline("Really quit?"); |
| 42 | if (readchar() != 'y') { |
| 43 | signal(SIGINT, done1); |
| 44 | clrlin(); |
| 45 | fflush(stdout); |
| 46 | if (multi > 0) |
| 47 | nomul(0); |
| 48 | return; |
| 49 | } |
| 50 | done("quit"); |
| 51 | /* NOTREACHED */ |
| 52 | } |
| 53 | |
| 54 | int done_stopprint; |
| 55 | int done_hup; |
| 56 | |
| 57 | static void |
| 58 | done_intr(int unused __unused) |
| 59 | { |
| 60 | done_stopprint++; |
| 61 | signal(SIGINT, SIG_IGN); |
| 62 | signal(SIGQUIT, SIG_IGN); |
| 63 | } |
| 64 | |
| 65 | static void |
| 66 | done_hangup(int unused __unused) |
| 67 | { |
| 68 | done_hup++; |
| 69 | signal(SIGHUP, SIG_IGN); |
| 70 | done_intr(0); |
| 71 | } |
| 72 | |
| 73 | void |
| 74 | done_in_by(struct monst *mtmp) |
| 75 | { |
| 76 | static char buf[BUFSZ]; |
| 77 | |
| 78 | pline("You die ..."); |
| 79 | if (mtmp->data->mlet == ' ') { |
| 80 | Sprintf(buf, "the ghost of %s", (char *)mtmp->mextra); |
| 81 | killer = buf; |
| 82 | } else if (mtmp->mnamelth) { |
| 83 | Sprintf(buf, "%s called %s", |
| 84 | mtmp->data->mname, NAME(mtmp)); |
| 85 | killer = buf; |
| 86 | } else if (mtmp->minvis) { |
| 87 | Sprintf(buf, "invisible %s", mtmp->data->mname); |
| 88 | killer = buf; |
| 89 | } else |
| 90 | killer = mtmp->data->mname; |
| 91 | done("died"); |
| 92 | } |
| 93 | |
| 94 | /* |
| 95 | * called with arg "died", "drowned", "escaped", "quit", "choked", |
| 96 | * "panicked", "burned", "starved" or "tricked" |
| 97 | */ |
| 98 | /* Be careful not to call panic from here! */ |
| 99 | void |
| 100 | done(const char *st1) |
| 101 | { |
| 102 | #ifdef WIZARD |
| 103 | if (wizard && *st1 == 'd') { |
| 104 | u.uswldtim = 0; |
| 105 | if (u.uhpmax < 0) /* arbitrary */ |
| 106 | u.uhpmax = 100; |
| 107 | u.uhp = u.uhpmax; |
| 108 | pline("For some reason you are still alive."); |
| 109 | flags.move = 0; |
| 110 | if (multi > 0) |
| 111 | multi = 0; |
| 112 | else |
| 113 | multi = -1; |
| 114 | flags.botl = 1; |
| 115 | return; |
| 116 | } |
| 117 | #endif /* WIZARD */ |
| 118 | signal(SIGINT, done_intr); |
| 119 | signal(SIGQUIT, done_intr); |
| 120 | signal(SIGHUP, done_hangup); |
| 121 | if (*st1 == 'q' && u.uhp < 1) { |
| 122 | st1 = "died"; |
| 123 | killer = "quit while already on Charon's boat"; |
| 124 | } |
| 125 | if (*st1 == 's') |
| 126 | killer = "starvation"; |
| 127 | else if (*st1 == 'd' && st1[1] == 'r') |
| 128 | killer = "drowning"; |
| 129 | else if (*st1 == 'p') |
| 130 | killer = "panic"; |
| 131 | else if (*st1 == 't') |
| 132 | killer = "trickery"; |
| 133 | else if (!strchr("bcd", *st1)) |
| 134 | killer = st1; |
| 135 | paybill(); |
| 136 | clearlocks(); |
| 137 | if (flags.toplin == 1) |
| 138 | more(); |
| 139 | if (strchr("bcds", *st1)) { |
| 140 | #ifdef WIZARD |
| 141 | if (!wizard) |
| 142 | #endif /* WIZARD */ |
| 143 | savebones(); |
| 144 | if (!flags.notombstone) |
| 145 | outrip(); |
| 146 | } |
| 147 | if (*st1 == 'c') /* after outrip() */ |
| 148 | killer = st1; |
| 149 | settty(NULL); /* does a clear_screen() */ |
| 150 | if (!done_stopprint) |
| 151 | printf("Goodbye %s %s...\n\n", pl_character, plname); |
| 152 | { |
| 153 | long int tmp; |
| 154 | tmp = u.ugold - u.ugold0; |
| 155 | if (tmp < 0) |
| 156 | tmp = 0; |
| 157 | if (*st1 == 'd' || *st1 == 'b') |
| 158 | tmp -= tmp / 10; |
| 159 | u.urexp += tmp; |
| 160 | u.urexp += 50 * maxdlevel; |
| 161 | if (maxdlevel > 20) |
| 162 | u.urexp += 1000 * ((maxdlevel > 30) ? 10 : maxdlevel - 20); |
| 163 | } |
| 164 | if (*st1 == 'e') { |
| 165 | struct monst *mtmp; |
| 166 | struct obj *otmp; |
| 167 | int i; |
| 168 | unsigned worthlessct = 0; |
| 169 | boolean has_amulet = FALSE; |
| 170 | |
| 171 | killer = st1; |
| 172 | keepdogs(); |
| 173 | mtmp = mydogs; |
| 174 | if (mtmp) { |
| 175 | if (!done_stopprint) |
| 176 | printf("You"); |
| 177 | while (mtmp) { |
| 178 | if (!done_stopprint) |
| 179 | printf(" and %s", monnam(mtmp)); |
| 180 | if (mtmp->mtame) |
| 181 | u.urexp += mtmp->mhp; |
| 182 | mtmp = mtmp->nmon; |
| 183 | } |
| 184 | if (!done_stopprint) |
| 185 | printf("\nescaped from the dungeon with %ld points,\n", |
| 186 | u.urexp); |
| 187 | } else if (!done_stopprint) |
| 188 | printf("You escaped from the dungeon with %ld points,\n", |
| 189 | u.urexp); |
| 190 | for (otmp = invent; otmp; otmp = otmp->nobj) { |
| 191 | if (otmp->olet == GEM_SYM) { |
| 192 | objects[otmp->otyp].oc_name_known = 1; |
| 193 | i = otmp->quan * objects[otmp->otyp].g_val; |
| 194 | if (i == 0) { |
| 195 | worthlessct += otmp->quan; |
| 196 | continue; |
| 197 | } |
| 198 | u.urexp += i; |
| 199 | if (!done_stopprint) |
| 200 | printf("\t%s (worth %d Zorkmids),\n", |
| 201 | doname(otmp), i); |
| 202 | } else if (otmp->olet == AMULET_SYM) { |
| 203 | otmp->known = 1; |
| 204 | i = (otmp->spe < 0) ? 2 : 5000; |
| 205 | u.urexp += i; |
| 206 | if (!done_stopprint) |
| 207 | printf("\t%s (worth %d Zorkmids),\n", |
| 208 | doname(otmp), i); |
| 209 | if (otmp->spe >= 0) { |
| 210 | has_amulet = TRUE; |
| 211 | killer = "escaped (with amulet)"; |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | if (worthlessct) |
| 216 | if (!done_stopprint) |
| 217 | printf("\t%u worthless piece%s of coloured glass,\n", |
| 218 | worthlessct, plur(worthlessct)); |
| 219 | if (has_amulet) |
| 220 | u.urexp *= 2; |
| 221 | } else if (!done_stopprint) |
| 222 | printf("You %s on dungeon level %d with %ld points,\n", |
| 223 | st1, dlevel, u.urexp); |
| 224 | if (!done_stopprint) |
| 225 | printf("and %ld piece%s of gold, after %ld move%s.\n", |
| 226 | u.ugold, plur(u.ugold), moves, plur(moves)); |
| 227 | if (!done_stopprint) |
| 228 | printf("You were level %u with a maximum of %d hit points when you %s.\n", |
| 229 | u.ulevel, u.uhpmax, st1); |
| 230 | if (*st1 == 'e' && !done_stopprint) { |
| 231 | getret(); /* all those pieces of coloured glass ... */ |
| 232 | cls(); |
| 233 | } |
| 234 | #ifdef WIZARD |
| 235 | if (!wizard) |
| 236 | #endif /* WIZARD */ |
| 237 | topten(); |
| 238 | if (done_stopprint) |
| 239 | printf("\n\n"); |
| 240 | exit(0); |
| 241 | } |
| 242 | |
| 243 | static void |
| 244 | topten(void) |
| 245 | { |
| 246 | int uid = getuid(); |
| 247 | int rank, rank0 = -1, rank1 = 0; |
| 248 | int occ_cnt = PERSMAX; |
| 249 | struct toptenentry *t0, *t1, *tprev; |
| 250 | const char *recfile = RECORD; |
| 251 | const char *reclock = "record_lock"; |
| 252 | int sleepct = 300; |
| 253 | FILE *rfile; |
| 254 | int flg = 0; |
| 255 | |
| 256 | #define HUP if (!done_hup) |
| 257 | while (link(recfile, reclock) == -1) { |
| 258 | HUP perror(reclock); |
| 259 | if (!sleepct--) { |
| 260 | HUP puts("I give up. Sorry."); |
| 261 | HUP puts("Perhaps there is an old record_lock around?"); |
| 262 | return; |
| 263 | } |
| 264 | HUP printf("Waiting for access to record file. (%d)\n", |
| 265 | sleepct); |
| 266 | HUP fflush(stdout); |
| 267 | sleep(1); |
| 268 | } |
| 269 | if (!(rfile = fopen(recfile, "r"))) { |
| 270 | HUP puts("Cannot open record file!"); |
| 271 | goto unlock; |
| 272 | } |
| 273 | HUP putchar('\n'); |
| 274 | |
| 275 | /* create a new 'topten' entry */ |
| 276 | t0 = newttentry(); |
| 277 | t0->level = dlevel; |
| 278 | t0->maxlvl = maxdlevel; |
| 279 | t0->hp = u.uhp; |
| 280 | t0->maxhp = u.uhpmax; |
| 281 | t0->points = u.urexp; |
| 282 | t0->plchar = pl_character[0]; |
| 283 | t0->sex = (flags.female ? 'F' : 'M'); |
| 284 | t0->uid = uid; |
| 285 | strncpy(t0->name, plname, NAMSZ); |
| 286 | (t0->name)[NAMSZ] = 0; |
| 287 | strncpy(t0->death, killer, DTHSZ); |
| 288 | (t0->death)[DTHSZ] = 0; |
| 289 | strcpy(t0->date, getdate()); |
| 290 | |
| 291 | /* assure minimum number of points */ |
| 292 | if (t0->points < POINTSMIN) |
| 293 | t0->points = 0; |
| 294 | |
| 295 | t1 = tt_head = newttentry(); |
| 296 | tprev = NULL; |
| 297 | /* rank0: -1 undefined, 0 not_on_list, n n_th on list */ |
| 298 | for (rank = 1;;) { |
| 299 | if (fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", |
| 300 | t1->date, &t1->uid, |
| 301 | &t1->level, &t1->maxlvl, |
| 302 | &t1->hp, &t1->maxhp, &t1->points, |
| 303 | &t1->plchar, &t1->sex, t1->name, t1->death) != 11 |
| 304 | || t1->points < POINTSMIN) |
| 305 | t1->points = 0; |
| 306 | if (rank0 < 0 && t1->points < t0->points) { |
| 307 | rank0 = rank++; |
| 308 | if (tprev == NULL) |
| 309 | tt_head = t0; |
| 310 | else |
| 311 | tprev->tt_next = t0; |
| 312 | t0->tt_next = t1; |
| 313 | occ_cnt--; |
| 314 | flg++; /* ask for a rewrite */ |
| 315 | } else |
| 316 | tprev = t1; |
| 317 | if (t1->points == 0) |
| 318 | break; |
| 319 | if ( |
| 320 | #ifdef PERS_IS_UID |
| 321 | t1->uid == t0->uid && |
| 322 | #else |
| 323 | strncmp(t1->name, t0->name, NAMSZ) == 0 && |
| 324 | #endif /* PERS_IS_UID */ |
| 325 | t1->plchar == t0->plchar && --occ_cnt <= 0) { |
| 326 | if (rank0 < 0) { |
| 327 | rank0 = 0; |
| 328 | rank1 = rank; |
| 329 | HUP printf("You didn't beat your previous score of %ld points.\n\n", |
| 330 | t1->points); |
| 331 | } |
| 332 | if (occ_cnt < 0) { |
| 333 | flg++; |
| 334 | continue; |
| 335 | } |
| 336 | } |
| 337 | if (rank <= ENTRYMAX) { |
| 338 | t1 = t1->tt_next = newttentry(); |
| 339 | rank++; |
| 340 | } |
| 341 | if (rank > ENTRYMAX) { |
| 342 | t1->points = 0; |
| 343 | break; |
| 344 | } |
| 345 | } |
| 346 | if (flg) { /* rewrite record file */ |
| 347 | fclose(rfile); |
| 348 | if (!(rfile = fopen(recfile, "w"))) { |
| 349 | HUP puts("Cannot write record file\n"); |
| 350 | goto unlock; |
| 351 | } |
| 352 | |
| 353 | if (!done_stopprint) |
| 354 | if (rank0 > 0) { |
| 355 | if (rank0 <= 10) |
| 356 | puts("You made the top ten list!\n"); |
| 357 | else |
| 358 | printf("You reached the %d%s place on the top %d list.\n\n", |
| 359 | rank0, ordin(rank0), ENTRYMAX); |
| 360 | } |
| 361 | } |
| 362 | if (rank0 == 0) |
| 363 | rank0 = rank1; |
| 364 | if (rank0 <= 0) |
| 365 | rank0 = rank; |
| 366 | if (!done_stopprint) |
| 367 | outheader(); |
| 368 | t1 = tt_head; |
| 369 | for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { |
| 370 | if (flg) |
| 371 | fprintf(rfile, "%6s %d %d %d %d %d %ld %c%c %s,%s\n", |
| 372 | t1->date, t1->uid, |
| 373 | t1->level, t1->maxlvl, |
| 374 | t1->hp, t1->maxhp, t1->points, |
| 375 | t1->plchar, t1->sex, t1->name, t1->death); |
| 376 | if (done_stopprint) |
| 377 | continue; |
| 378 | if (rank > (int)flags.end_top && |
| 379 | (rank < rank0 - (int)flags.end_around || rank > rank0 + |
| 380 | (int)flags.end_around) |
| 381 | && (!flags.end_own || |
| 382 | #ifdef PERS_IS_UID |
| 383 | t1->uid != t0->uid)) |
| 384 | #else |
| 385 | strncmp(t1->name, t0->name, NAMSZ))) |
| 386 | #endif /* PERS_IS_UID */ |
| 387 | continue; |
| 388 | if (rank == rank0 - (int)flags.end_around && |
| 389 | rank0 > (int)flags.end_top + (int)flags.end_around + 1 && |
| 390 | !flags.end_own) |
| 391 | putchar('\n'); |
| 392 | if (rank != rank0) |
| 393 | outentry(rank, t1, 0); |
| 394 | else if (!rank1) |
| 395 | outentry(rank, t1, 1); |
| 396 | else { |
| 397 | int t0lth = outentry(0, t0, -1); |
| 398 | int t1lth = outentry(rank, t1, t0lth); |
| 399 | if (t1lth > t0lth) |
| 400 | t0lth = t1lth; |
| 401 | outentry(0, t0, t0lth); |
| 402 | } |
| 403 | } |
| 404 | if (rank0 >= rank) |
| 405 | if (!done_stopprint) |
| 406 | outentry(0, t0, 1); |
| 407 | fclose(rfile); |
| 408 | unlock: |
| 409 | unlink(reclock); |
| 410 | } |
| 411 | |
| 412 | static void |
| 413 | outheader(void) |
| 414 | { |
| 415 | char linebuf[BUFSZ]; |
| 416 | char *bp; |
| 417 | |
| 418 | strcpy(linebuf, "Number Points Name"); |
| 419 | bp = eos(linebuf); |
| 420 | while (bp < linebuf + COLNO - 9) |
| 421 | *bp++ = ' '; |
| 422 | strcpy(bp, "Hp [max]"); |
| 423 | puts(linebuf); |
| 424 | } |
| 425 | |
| 426 | /* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */ |
| 427 | static int |
| 428 | outentry(int rank, struct toptenentry *t1, int so) |
| 429 | { |
| 430 | boolean quit = FALSE, dead = FALSE, starv = FALSE; |
| 431 | char linebuf[BUFSZ]; |
| 432 | |
| 433 | linebuf[0] = 0; |
| 434 | if (rank) |
| 435 | Sprintf(eos(linebuf), "%3d", rank); |
| 436 | else |
| 437 | Sprintf(eos(linebuf), " "); |
| 438 | Sprintf(eos(linebuf), " %6ld %8s", t1->points, t1->name); |
| 439 | if (t1->plchar == 'X') |
| 440 | Sprintf(eos(linebuf), " "); |
| 441 | else |
| 442 | Sprintf(eos(linebuf), "-%c ", t1->plchar); |
| 443 | if (!strncmp("escaped", t1->death, 7)) { |
| 444 | if (!strcmp(" (with amulet)", t1->death + 7)) |
| 445 | Sprintf(eos(linebuf), "escaped the dungeon with amulet"); |
| 446 | else |
| 447 | Sprintf(eos(linebuf), "escaped the dungeon [max level %d]", |
| 448 | t1->maxlvl); |
| 449 | } else { |
| 450 | if (!strncmp(t1->death, "quit", 4)) { |
| 451 | quit = TRUE; |
| 452 | if (t1->maxhp < 3 * t1->hp && t1->maxlvl < 4) |
| 453 | Sprintf(eos(linebuf), "cravenly gave up"); |
| 454 | else |
| 455 | Sprintf(eos(linebuf), "quit"); |
| 456 | } else if (!strcmp(t1->death, "choked")) { |
| 457 | Sprintf(eos(linebuf), "choked on %s food", |
| 458 | (t1->sex == 'F') ? "her" : "his"); |
| 459 | } else if (!strncmp(t1->death, "starv", 5)) { |
| 460 | Sprintf(eos(linebuf), "starved to death"); |
| 461 | starv = TRUE; |
| 462 | } else { |
| 463 | Sprintf(eos(linebuf), "was killed"); |
| 464 | dead = TRUE; |
| 465 | } |
| 466 | Sprintf(eos(linebuf), " on%s level %d", |
| 467 | (dead || starv) ? "" : " dungeon", t1->level); |
| 468 | if (t1->maxlvl != t1->level) |
| 469 | Sprintf(eos(linebuf), " [max %d]", t1->maxlvl); |
| 470 | if (quit && t1->death[4]) |
| 471 | Sprintf(eos(linebuf), "%s", t1->death + 4); |
| 472 | } |
| 473 | if (dead) { |
| 474 | Sprintf(eos(linebuf), " by %s%s", |
| 475 | (!strncmp(t1->death, "trick", 5) || |
| 476 | !strncmp(t1->death, "the ", 4)) |
| 477 | ? "" : |
| 478 | strchr(vowels, *t1->death) ? "an " : "a ", |
| 479 | t1->death); |
| 480 | } |
| 481 | Sprintf(eos(linebuf), "."); |
| 482 | if (t1->maxhp) { |
| 483 | char *bp = eos(linebuf); |
| 484 | char hpbuf[10]; |
| 485 | int hppos; |
| 486 | |
| 487 | Sprintf(hpbuf, "%s", (t1->hp > 0) ? itoa(t1->hp) : "-"); |
| 488 | hppos = COLNO - 7 - strlen(hpbuf); |
| 489 | if (bp <= linebuf + hppos) { |
| 490 | while (bp < linebuf + hppos) |
| 491 | *bp++ = ' '; |
| 492 | strcpy(bp, hpbuf); |
| 493 | Sprintf(eos(bp), " [%d]", t1->maxhp); |
| 494 | } |
| 495 | } |
| 496 | if (so == 0) |
| 497 | puts(linebuf); |
| 498 | else if (so > 0) { |
| 499 | char *bp = eos(linebuf); |
| 500 | if (so >= COLNO) |
| 501 | so = COLNO - 1; |
| 502 | while (bp < linebuf + so) |
| 503 | *bp++ = ' '; |
| 504 | *bp = 0; |
| 505 | standoutbeg(); |
| 506 | fputs(linebuf, stdout); |
| 507 | standoutend(); |
| 508 | putchar('\n'); |
| 509 | } |
| 510 | return (strlen(linebuf)); |
| 511 | } |
| 512 | |
| 513 | static char * |
| 514 | itoa(int a) |
| 515 | { |
| 516 | static char buf[12]; |
| 517 | |
| 518 | Sprintf(buf, "%d", a); |
| 519 | return (buf); |
| 520 | } |
| 521 | |
| 522 | static const char * |
| 523 | ordin(int n) |
| 524 | { |
| 525 | int d1 = n % 10; |
| 526 | |
| 527 | return ((d1 == 0 || d1 > 3 || n / 10 == 1) ? "th" : (d1 == 1) ? "st" : |
| 528 | (d1 == 2) ? "nd" : "rd"); |
| 529 | } |
| 530 | |
| 531 | void |
| 532 | clearlocks(void) |
| 533 | { |
| 534 | int x; |
| 535 | |
| 536 | signal(SIGHUP, SIG_IGN); |
| 537 | for (x = maxdlevel; x >= 0; x--) { |
| 538 | glo(x); |
| 539 | unlink(lock); /* not all levels need be present */ |
| 540 | } |
| 541 | } |
| 542 | |
| 543 | #ifdef NOSAVEONHANGUP |
| 544 | void |
| 545 | hangup(int unused __unused) |
| 546 | { |
| 547 | signal(SIGINT, SIG_IGN); |
| 548 | clearlocks(); |
| 549 | exit(1); |
| 550 | } |
| 551 | #endif /* NOSAVEONHANGUP */ |
| 552 | |
| 553 | char * |
| 554 | eos(char *s) |
| 555 | { |
| 556 | while (*s) |
| 557 | s++; |
| 558 | return (s); |
| 559 | } |
| 560 | |
| 561 | /* it is the callers responsibility to check that there is room for c */ |
| 562 | void |
| 563 | charcat(char *s, char c) |
| 564 | { |
| 565 | while (*s) |
| 566 | s++; |
| 567 | *s++ = c; |
| 568 | *s = 0; |
| 569 | } |
| 570 | |
| 571 | /* |
| 572 | * Called with args from main if argc >= 0. In this case, list scores as |
| 573 | * requested. Otherwise, find scores for the current player (and list them |
| 574 | * if argc == -1). |
| 575 | */ |
| 576 | void |
| 577 | prscore(int argc, char **argv) |
| 578 | { |
| 579 | char **players = NULL; |
| 580 | int playerct; |
| 581 | int rank; |
| 582 | struct toptenentry *t1, *t2; |
| 583 | const char *recfile = RECORD; |
| 584 | FILE *rfile; |
| 585 | int flg = 0; |
| 586 | int i; |
| 587 | #ifdef nonsense |
| 588 | long total_score = 0L; |
| 589 | char totchars[10]; |
| 590 | int totcharct = 0; |
| 591 | #endif /* nonsense */ |
| 592 | int outflg = (argc >= -1); |
| 593 | #ifdef PERS_IS_UID |
| 594 | int uid = -1; |
| 595 | #else |
| 596 | char *player0; |
| 597 | #endif /* PERS_IS_UID */ |
| 598 | |
| 599 | if (!(rfile = fopen(recfile, "r"))) { |
| 600 | puts("Cannot open record file!"); |
| 601 | return; |
| 602 | } |
| 603 | |
| 604 | if (argc > 1 && !strncmp(argv[1], "-s", 2)) { |
| 605 | if (!argv[1][2]) { |
| 606 | argc--; |
| 607 | argv++; |
| 608 | } else if (!argv[1][3] && strchr("CFKSTWX", argv[1][2])) { |
| 609 | argv[1]++; |
| 610 | argv[1][0] = '-'; |
| 611 | } else |
| 612 | argv[1] += 2; |
| 613 | } |
| 614 | if (argc <= 1) { |
| 615 | #ifdef PERS_IS_UID |
| 616 | uid = getuid(); |
| 617 | playerct = 0; |
| 618 | #else |
| 619 | player0 = plname; |
| 620 | if (!*player0) |
| 621 | player0 = "hackplayer"; |
| 622 | playerct = 1; |
| 623 | players = &player0; |
| 624 | #endif /* PERS_IS_UID */ |
| 625 | } else { |
| 626 | playerct = --argc; |
| 627 | players = ++argv; |
| 628 | } |
| 629 | if (outflg) |
| 630 | putchar('\n'); |
| 631 | |
| 632 | t1 = tt_head = newttentry(); |
| 633 | for (rank = 1;; rank++) { |
| 634 | if (fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", |
| 635 | t1->date, &t1->uid, |
| 636 | &t1->level, &t1->maxlvl, |
| 637 | &t1->hp, &t1->maxhp, &t1->points, |
| 638 | &t1->plchar, &t1->sex, t1->name, t1->death) != 11) |
| 639 | t1->points = 0; |
| 640 | if (t1->points == 0) |
| 641 | break; |
| 642 | #ifdef PERS_IS_UID |
| 643 | if (!playerct && t1->uid == uid) |
| 644 | flg++; |
| 645 | else |
| 646 | #endif /* PERS_IS_UID */ |
| 647 | for (i = 0; i < playerct; i++) { |
| 648 | if (strcmp(players[i], "all") == 0 || |
| 649 | strncmp(t1->name, players[i], NAMSZ) == 0 || |
| 650 | (players[i][0] == '-' && |
| 651 | players[i][1] == t1->plchar && |
| 652 | players[i][2] == 0) || |
| 653 | (digit(players[i][0]) && rank <= atoi(players[i]))) |
| 654 | flg++; |
| 655 | } |
| 656 | t1 = t1->tt_next = newttentry(); |
| 657 | } |
| 658 | fclose(rfile); |
| 659 | if (!flg) { |
| 660 | if (outflg) { |
| 661 | printf("Cannot find any entries for "); |
| 662 | if (playerct < 1) |
| 663 | printf("you.\n"); |
| 664 | else { |
| 665 | if (playerct > 1) |
| 666 | printf("any of "); |
| 667 | for (i = 0; i < playerct; i++) |
| 668 | printf("%s%s", players[i], |
| 669 | (i < playerct - 1) ? ", " : ".\n"); |
| 670 | printf("Call is: %s -s [playernames]\n", hname); |
| 671 | } |
| 672 | } |
| 673 | return; |
| 674 | } |
| 675 | |
| 676 | if (outflg) |
| 677 | outheader(); |
| 678 | t1 = tt_head; |
| 679 | for (rank = 1; t1->points != 0; rank++, t1 = t2) { |
| 680 | t2 = t1->tt_next; |
| 681 | #ifdef PERS_IS_UID |
| 682 | if (!playerct && t1->uid == uid) |
| 683 | goto outwithit; |
| 684 | else |
| 685 | #endif /* PERS_IS_UID */ |
| 686 | for (i = 0; i < playerct; i++) { |
| 687 | if (strcmp(players[i], "all") == 0 || |
| 688 | strncmp(t1->name, players[i], NAMSZ) == 0 || |
| 689 | (players[i][0] == '-' && |
| 690 | players[i][1] == t1->plchar && |
| 691 | players[i][2] == 0) || |
| 692 | (digit(players[i][0]) && rank <= |
| 693 | atoi(players[i]))) { |
| 694 | outwithit: |
| 695 | if (outflg) |
| 696 | outentry(rank, t1, 0); |
| 697 | #ifdef nonsense |
| 698 | total_score += t1->points; |
| 699 | if (totcharct < sizeof(totchars) - 1) |
| 700 | totchars[totcharct++] = t1->plchar; |
| 701 | #endif /* nonsense */ |
| 702 | break; |
| 703 | } |
| 704 | } |
| 705 | free(t1); |
| 706 | } |
| 707 | #ifdef nonsense |
| 708 | totchars[totcharct] = 0; |
| 709 | |
| 710 | /* |
| 711 | * We would like to determine whether he is experienced. However, the |
| 712 | * information collected here only tells about the scores/roles that |
| 713 | * got into the topten (top 100?). We should maintain a .hacklog or |
| 714 | * something in his home directory. |
| 715 | */ |
| 716 | flags.beginner = (total_score < 6000); |
| 717 | for (i = 0; i < 6; i++) |
| 718 | if (!strchr(totchars, "CFKSTWX"[i])) { |
| 719 | flags.beginner = 1; |
| 720 | if (!pl_character[0]) |
| 721 | pl_character[0] = "CFKSTWX"[i]; |
| 722 | break; |
| 723 | } |
| 724 | #endif /* nonsense */ |
| 725 | } |