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