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