hack.end.c revision 1.12 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 (at) 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