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