OSDN Git Service

eliminate warnings
[jnethack/source.git] / src / topten.c
1 /* NetHack 3.6  topten.c        $NHDT-Date: 1448117546 2015/11/21 14:52:26 $  $NHDT-Branch: master $:$NHDT-Revision: 1.40 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016            */
8 /* JNetHack may be freely redistributed.  See license for details. */
9
10 #include "hack.h"
11 #include "dlb.h"
12 #ifdef SHORT_FILENAMES
13 #include "patchlev.h"
14 #else
15 #include "patchlevel.h"
16 #endif
17
18 #ifdef VMS
19 /* We don't want to rewrite the whole file, because that entails
20    creating a new version which requires that the old one be deletable. */
21 #define UPDATE_RECORD_IN_PLACE
22 #endif
23
24 /*
25  * Updating in place can leave junk at the end of the file in some
26  * circumstances (if it shrinks and the O.S. doesn't have a straightforward
27  * way to truncate it).  The trailing junk is harmless and the code
28  * which reads the scores will ignore it.
29  */
30 #ifdef UPDATE_RECORD_IN_PLACE
31 static long final_fpos;
32 #endif
33
34 #define done_stopprint program_state.stopprint
35
36 #define newttentry() (struct toptenentry *) alloc(sizeof (struct toptenentry))
37 #define dealloc_ttentry(ttent) free((genericptr_t) (ttent))
38 #define NAMSZ 10
39 #define DTHSZ 100
40 #define ROLESZ 3
41
42 struct toptenentry {
43     struct toptenentry *tt_next;
44 #ifdef UPDATE_RECORD_IN_PLACE
45     long fpos;
46 #endif
47     long points;
48     int deathdnum, deathlev;
49     int maxlvl, hp, maxhp, deaths;
50     int ver_major, ver_minor, patchlevel;
51     long deathdate, birthdate;
52     int uid;
53     char plrole[ROLESZ + 1];
54     char plrace[ROLESZ + 1];
55     char plgend[ROLESZ + 1];
56     char plalign[ROLESZ + 1];
57     char name[NAMSZ + 1];
58     char death[DTHSZ + 1];
59 } * tt_head;
60 /* size big enough to read in all the string fields at once; includes
61    room for separating space or trailing newline plus string terminator */
62 #define SCANBUFSZ (4 * (ROLESZ + 1) + (NAMSZ + 1) + (DTHSZ + 1) + 1)
63
64 STATIC_DCL void FDECL(topten_print, (const char *));
65 STATIC_DCL void FDECL(topten_print_bold, (const char *));
66 STATIC_DCL xchar FDECL(observable_depth, (d_level *));
67 STATIC_DCL void NDECL(outheader);
68 STATIC_DCL void FDECL(outentry, (int, struct toptenentry *, BOOLEAN_P));
69 STATIC_DCL void FDECL(discardexcess, (FILE *));
70 STATIC_DCL void FDECL(readentry, (FILE *, struct toptenentry *));
71 STATIC_DCL void FDECL(writeentry, (FILE *, struct toptenentry *));
72 STATIC_DCL void FDECL(writexlentry, (FILE *, struct toptenentry *));
73 STATIC_DCL long NDECL(encodexlogflags);
74 STATIC_DCL long NDECL(encodeconduct);
75 STATIC_DCL long NDECL(encodeachieve);
76 STATIC_DCL void FDECL(free_ttlist, (struct toptenentry *));
77 STATIC_DCL int FDECL(classmon, (char *, BOOLEAN_P));
78 STATIC_DCL int FDECL(score_wanted, (BOOLEAN_P, int, struct toptenentry *, int,
79                                     const char **, int));
80 #ifdef NO_SCAN_BRACK
81 STATIC_DCL void FDECL(nsb_mung_line, (char *));
82 STATIC_DCL void FDECL(nsb_unmung_line, (char *));
83 #endif
84
85 static winid toptenwin = WIN_ERR;
86
87 /* "killed by",&c ["an"] 'killer.name' */
88 void
89 formatkiller(buf, siz, how)
90 char *buf;
91 unsigned siz;
92 int how;
93 {
94     static NEARDATA const char *const killed_by_prefix[] = {
95         /* DIED, CHOKING, POISONING, STARVING, */
96 /*JP
97         "killed by ", "choked on ", "poisoned by ", "died of ",
98 */
99         "\8e\80\82ñ\82¾", "\82Å\92\82\91§\82µ\82½", "\82Ì\93Å\82Å\8e\80\82ñ\82¾", "",
100         /* DROWNING, BURNING, DISSOLVED, CRUSHING, */
101 /*JP
102         "drowned in ", "burned by ", "dissolved in ", "crushed to death by ",
103 */
104          "\93M\8e\80\82µ\82½","\8fÄ\8e\80\82µ\82½", "\97n\8aâ\82É\97n\82¯\82½", "\89\9f\82µ\92×\82³\82ê\82½",
105         /* STONING, TURNED_SLIME, GENOCIDED, */
106 /*JP
107         "petrified by ", "turned to slime by ", "killed by ",
108 */
109          "\90Î\82É\82È\82Á\82½", "\82É\83X\83\89\83C\83\80\82É\82³\82ê\82½", "\8bs\8eE\82³\82ê\82½",
110         /* PANICKED, TRICKED, QUIT, ESCAPED, ASCENDED */
111         "", "", "", "", ""
112     };
113 #if 0 /*JP*/
114     unsigned l;
115 #endif
116     char *kname = killer.name;
117
118     buf[0] = '\0'; /* so strncat() can find the end */
119 #if 1 /*JP*//*\90æ\82É\91Î\8fÛ\82ð\83R\83s\81[*/
120     strncat(buf, kname, siz - 1);
121     siz -= strlen(buf);
122 #endif
123     switch (killer.format) {
124     default:
125         impossible("bad killer format? (%d)", killer.format);
126         /*FALLTHRU*/
127     case NO_KILLER_PREFIX:
128         break;
129     case KILLED_BY_AN:
130 #if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\95s\97v*/
131         kname = an(kname);
132 #endif
133         /*FALLTHRU*/
134     case KILLED_BY:
135 #if 0 /*JP*/
136         (void) strncat(buf, killed_by_prefix[how], siz - 1);
137         l = strlen(buf);
138         buf += l, siz -= l;
139 #else /*JP:\8aù\82É\91Î\8fÛ\82ð\83R\83s\81[\82µ\82Ä\82¢\82é\82Ì\82Å\92P\82É\92Ç\89Á*/
140         (void) strncat(buf, killed_by_prefix[how], siz - 1);
141 #endif
142         break;
143 #if 1 /*JP*/
144       case KILLED_SUFFIX:
145         (void) strncat(buf, "\82É\8eE\82³\82ê\82½", siz - 1);
146 #endif
147     }
148 #if 0 /*JP*//*\8aù\82É\83R\83s\81[\8dÏ\82Ý*/
149     /* we're writing into buf[0] (after possibly advancing buf) rather than
150        appending, but strncat() appends a terminator and strncpy() doesn't */
151     (void) strncat(buf, kname, siz - 1);
152 #endif
153 }
154
155 STATIC_OVL void
156 topten_print(x)
157 const char *x;
158 {
159     if (toptenwin == WIN_ERR)
160         raw_print(x);
161     else
162         putstr(toptenwin, ATR_NONE, x);
163 }
164
165 STATIC_OVL void
166 topten_print_bold(x)
167 const char *x;
168 {
169     if (toptenwin == WIN_ERR)
170         raw_print_bold(x);
171     else
172         putstr(toptenwin, ATR_BOLD, x);
173 }
174
175 STATIC_OVL xchar
176 observable_depth(lev)
177 d_level *lev;
178 {
179 #if 0
180     /* if we ever randomize the order of the elemental planes, we
181        must use a constant external representation in the record file */
182     if (In_endgame(lev)) {
183         if (Is_astralevel(lev))
184             return -5;
185         else if (Is_waterlevel(lev))
186             return -4;
187         else if (Is_firelevel(lev))
188             return -3;
189         else if (Is_airlevel(lev))
190             return -2;
191         else if (Is_earthlevel(lev))
192             return -1;
193         else
194             return 0; /* ? */
195     } else
196 #endif
197     return depth(lev);
198 }
199
200 /* throw away characters until current record has been entirely consumed */
201 STATIC_OVL void
202 discardexcess(rfile)
203 FILE *rfile;
204 {
205     int c;
206
207     do {
208         c = fgetc(rfile);
209     } while (c != '\n' && c != EOF);
210 }
211
212 STATIC_OVL void
213 readentry(rfile, tt)
214 FILE *rfile;
215 struct toptenentry *tt;
216 {
217     char inbuf[SCANBUFSZ], s1[SCANBUFSZ], s2[SCANBUFSZ], s3[SCANBUFSZ],
218         s4[SCANBUFSZ], s5[SCANBUFSZ], s6[SCANBUFSZ];
219
220 #ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
221     static const char fmt[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c";
222     static const char fmt32[] = "%c%c %s %s%*c";
223     static const char fmt33[] = "%s %s %s %s %s %s%*c";
224 #else
225     static const char fmt[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
226     static const char fmt32[] = "%c%c %[^,],%[^\n]%*c";
227     static const char fmt33[] = "%s %s %s %s %[^,],%[^\n]%*c";
228 #endif
229
230 #ifdef UPDATE_RECORD_IN_PLACE
231     /* note: input below must read the record's terminating newline */
232     final_fpos = tt->fpos = ftell(rfile);
233 #endif
234 #define TTFIELDS 13
235     if (fscanf(rfile, fmt, &tt->ver_major, &tt->ver_minor, &tt->patchlevel,
236                &tt->points, &tt->deathdnum, &tt->deathlev, &tt->maxlvl,
237                &tt->hp, &tt->maxhp, &tt->deaths, &tt->deathdate,
238                &tt->birthdate, &tt->uid) != TTFIELDS) {
239 #undef TTFIELDS
240         tt->points = 0;
241         discardexcess(rfile);
242     } else {
243         /* load remainder of record into a local buffer;
244            this imposes an implicit length limit of SCANBUFSZ
245            on every string field extracted from the buffer */
246         if (!fgets(inbuf, sizeof inbuf, rfile)) {
247             /* sscanf will fail and tt->points will be set to 0 */
248             *inbuf = '\0';
249         } else if (!index(inbuf, '\n')) {
250             Strcpy(&inbuf[sizeof inbuf - 2], "\n");
251             discardexcess(rfile);
252         }
253         /* Check for backwards compatibility */
254         if (tt->ver_major < 3 || (tt->ver_major == 3 && tt->ver_minor < 3)) {
255             int i;
256
257             if (sscanf(inbuf, fmt32, tt->plrole, tt->plgend, s1, s2) == 4) {
258                 tt->plrole[1] = tt->plgend[1] = '\0'; /* read via %c */
259                 copynchars(tt->name, s1, (int) (sizeof tt->name) - 1);
260                 copynchars(tt->death, s2, (int) (sizeof tt->death) - 1);
261             } else
262                 tt->points = 0;
263             tt->plrole[1] = '\0';
264             if ((i = str2role(tt->plrole)) >= 0)
265                 Strcpy(tt->plrole, roles[i].filecode);
266             Strcpy(tt->plrace, "?");
267             Strcpy(tt->plgend, (tt->plgend[0] == 'M') ? "Mal" : "Fem");
268             Strcpy(tt->plalign, "?");
269         } else if (sscanf(inbuf, fmt33, s1, s2, s3, s4, s5, s6) == 6) {
270             copynchars(tt->plrole, s1, (int) (sizeof tt->plrole) - 1);
271             copynchars(tt->plrace, s2, (int) (sizeof tt->plrace) - 1);
272             copynchars(tt->plgend, s3, (int) (sizeof tt->plgend) - 1);
273             copynchars(tt->plalign, s4, (int) (sizeof tt->plalign) - 1);
274             copynchars(tt->name, s5, (int) (sizeof tt->name) - 1);
275             copynchars(tt->death, s6, (int) (sizeof tt->death) - 1);
276         } else
277             tt->points = 0;
278 #ifdef NO_SCAN_BRACK
279         if (tt->points > 0) {
280             nsb_unmung_line(tt->name);
281             nsb_unmung_line(tt->death);
282         }
283 #endif
284     }
285
286     /* check old score entries for Y2K problem and fix whenever found */
287     if (tt->points > 0) {
288         if (tt->birthdate < 19000000L)
289             tt->birthdate += 19000000L;
290         if (tt->deathdate < 19000000L)
291             tt->deathdate += 19000000L;
292     }
293 }
294
295 STATIC_OVL void
296 writeentry(rfile, tt)
297 FILE *rfile;
298 struct toptenentry *tt;
299 {
300     static const char fmt32[] = "%c%c ";        /* role,gender */
301     static const char fmt33[] = "%s %s %s %s "; /* role,race,gndr,algn */
302 #ifndef NO_SCAN_BRACK
303     static const char fmt0[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
304     static const char fmtX[] = "%s,%s%s%s\n";
305 #else /* NO_SCAN_BRACK */
306     static const char fmt0[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d ";
307     static const char fmtX[] = "%s %s%s%s\n";
308
309     nsb_mung_line(tt->name);
310     nsb_mung_line(tt->death);
311 #endif
312
313     (void) fprintf(rfile, fmt0, tt->ver_major, tt->ver_minor, tt->patchlevel,
314                    tt->points, tt->deathdnum, tt->deathlev, tt->maxlvl,
315                    tt->hp, tt->maxhp, tt->deaths, tt->deathdate,
316                    tt->birthdate, tt->uid);
317     if (tt->ver_major < 3 || (tt->ver_major == 3 && tt->ver_minor < 3))
318         (void) fprintf(rfile, fmt32, tt->plrole[0], tt->plgend[0]);
319     else
320         (void) fprintf(rfile, fmt33, tt->plrole, tt->plrace, tt->plgend,
321                        tt->plalign);
322 #if 0 /*JP*/
323     (void) fprintf(rfile, fmtX, onlyspace(tt->name) ? "_" : tt->name,
324                    tt->death,
325                    (multi ? ", while " : ""),
326                    (multi ? (multi_reason ? multi_reason : "helpless") : ""));
327 #else
328     (void) fprintf(rfile, fmtX, onlyspace(tt->name) ? "_" : tt->name,
329                    (multi ? (multi_reason ? multi_reason : "\96³\97Í\82È\8aÔ\82É") : ""),
330                    tt->death,
331                    "");
332 #endif
333
334 #ifdef NO_SCAN_BRACK
335     nsb_unmung_line(tt->name);
336     nsb_unmung_line(tt->death);
337 #endif
338 }
339
340 /* as tab is never used in eg. plname or death, no need to mangle those. */
341 STATIC_OVL void
342 writexlentry(rfile, tt)
343 FILE *rfile;
344 struct toptenentry *tt;
345 {
346 #define Fprintf (void) fprintf
347 #define XLOG_SEP '\t' /* xlogfile field separator. */
348     char buf[BUFSZ];
349
350     Sprintf(buf, "version=%d.%d.%d", tt->ver_major, tt->ver_minor,
351             tt->patchlevel);
352     Sprintf(eos(buf), "%cpoints=%ld%cdeathdnum=%d%cdeathlev=%d", XLOG_SEP,
353             tt->points, XLOG_SEP, tt->deathdnum, XLOG_SEP, tt->deathlev);
354     Sprintf(eos(buf), "%cmaxlvl=%d%chp=%d%cmaxhp=%d", XLOG_SEP, tt->maxlvl,
355             XLOG_SEP, tt->hp, XLOG_SEP, tt->maxhp);
356     Sprintf(eos(buf), "%cdeaths=%d%cdeathdate=%ld%cbirthdate=%ld%cuid=%d",
357             XLOG_SEP, tt->deaths, XLOG_SEP, tt->deathdate, XLOG_SEP,
358             tt->birthdate, XLOG_SEP, tt->uid);
359     Fprintf(rfile, "%s", buf);
360     Sprintf(buf, "%crole=%s%crace=%s%cgender=%s%calign=%s", XLOG_SEP,
361             tt->plrole, XLOG_SEP, tt->plrace, XLOG_SEP, tt->plgend, XLOG_SEP,
362             tt->plalign);
363     Fprintf(rfile, "%s%cname=%s%cdeath=%s",
364             buf, /* (already includes separator) */
365             XLOG_SEP, plname, XLOG_SEP, tt->death);
366     if (multi)
367 #if 0 /*JP*/
368         Fprintf(rfile, "%cwhile=%s", XLOG_SEP,
369                 multi_reason ? multi_reason : "helpless");
370 #else
371         Fprintf(rfile, "%cwhile=%s", XLOG_SEP,
372                 multi_reason ? multi_reason : "\96³\97Í\82È\8aÔ\82É");
373 #endif
374     Fprintf(rfile, "%cconduct=0x%lx%cturns=%ld%cachieve=0x%lx", XLOG_SEP,
375             encodeconduct(), XLOG_SEP, moves, XLOG_SEP, encodeachieve());
376     Fprintf(rfile, "%crealtime=%ld%cstarttime=%ld%cendtime=%ld", XLOG_SEP,
377 #if 0 /*C360-19*/
378             (long) urealtime.realtime, XLOG_SEP, (long) ubirthday, XLOG_SEP,
379             (long) urealtime.endtime);
380 #else
381             (long) urealtime.realtime, XLOG_SEP,
382             (long) ubirthday, XLOG_SEP, (long) urealtime.finish_time);
383 #endif
384     Fprintf(rfile, "%cgender0=%s%calign0=%s", XLOG_SEP,
385             genders[flags.initgend].filecode, XLOG_SEP,
386             aligns[1 - u.ualignbase[A_ORIGINAL]].filecode);
387     Fprintf(rfile, "%cflags=0x%lx", XLOG_SEP, encodexlogflags());
388     Fprintf(rfile, "\n");
389 #undef XLOG_SEP
390 }
391
392 STATIC_OVL long
393 encodexlogflags()
394 {
395     long e = 0L;
396
397     if (wizard)
398         e |= 1L << 0;
399     if (discover)
400         e |= 1L << 1;
401     if (!u.uroleplay.numbones)
402         e |= 1L << 2;
403
404     return e;
405 }
406
407 STATIC_OVL long
408 encodeconduct()
409 {
410     long e = 0L;
411
412     if (!u.uconduct.food)
413         e |= 1L << 0;
414     if (!u.uconduct.unvegan)
415         e |= 1L << 1;
416     if (!u.uconduct.unvegetarian)
417         e |= 1L << 2;
418     if (!u.uconduct.gnostic)
419         e |= 1L << 3;
420     if (!u.uconduct.weaphit)
421         e |= 1L << 4;
422     if (!u.uconduct.killer)
423         e |= 1L << 5;
424     if (!u.uconduct.literate)
425         e |= 1L << 6;
426     if (!u.uconduct.polypiles)
427         e |= 1L << 7;
428     if (!u.uconduct.polyselfs)
429         e |= 1L << 8;
430     if (!u.uconduct.wishes)
431         e |= 1L << 9;
432     if (!u.uconduct.wisharti)
433         e |= 1L << 10;
434     if (!num_genocides())
435         e |= 1L << 11;
436
437     return e;
438 }
439
440 STATIC_OVL long
441 encodeachieve()
442 {
443     long r = 0L;
444
445     if (u.uachieve.bell)
446         r |= 1L << 0;
447     if (u.uachieve.enter_gehennom)
448         r |= 1L << 1;
449     if (u.uachieve.menorah)
450         r |= 1L << 2;
451     if (u.uachieve.book)
452         r |= 1L << 3;
453     if (u.uevent.invoked)
454         r |= 1L << 4;
455     if (u.uachieve.amulet)
456         r |= 1L << 5;
457     if (In_endgame(&u.uz))
458         r |= 1L << 6;
459     if (Is_astralevel(&u.uz))
460         r |= 1L << 7;
461     if (u.uachieve.ascended)
462         r |= 1L << 8;
463     if (u.uachieve.mines_luckstone)
464         r |= 1L << 9;
465     if (u.uachieve.finish_sokoban)
466         r |= 1L << 10;
467     if (u.uachieve.killed_medusa)
468         r |= 1L << 11;
469     if (u.uroleplay.blind)
470         r |= 1L << 12;
471     if (u.uroleplay.nudist)
472         r |= 1L << 13;
473
474     return r;
475 }
476
477 STATIC_OVL void
478 free_ttlist(tt)
479 struct toptenentry *tt;
480 {
481     struct toptenentry *ttnext;
482
483     while (tt->points > 0) {
484         ttnext = tt->tt_next;
485         dealloc_ttentry(tt);
486         tt = ttnext;
487     }
488     dealloc_ttentry(tt);
489 }
490
491 void
492 topten(how, when)
493 int how;
494 time_t when;
495 {
496     int uid = getuid();
497     int rank, rank0 = -1, rank1 = 0;
498     int occ_cnt = sysopt.persmax;
499     register struct toptenentry *t0, *tprev;
500     struct toptenentry *t1;
501     FILE *rfile;
502     register int flg = 0;
503     boolean t0_used;
504 #ifdef LOGFILE
505     FILE *lfile;
506 #endif /* LOGFILE */
507 #ifdef XLOGFILE
508     FILE *xlfile;
509 #endif /* XLOGFILE */
510
511 #ifdef _DCC
512     /* Under DICE 3.0, this crashes the system consistently, apparently due to
513      * corruption of *rfile somewhere.  Until I figure this out, just cut out
514      * topten support entirely - at least then the game exits cleanly.  --AC
515      */
516     return;
517 #endif
518
519     /* If we are in the midst of a panic, cut out topten entirely.
520      * topten uses alloc() several times, which will lead to
521      * problems if the panic was the result of an alloc() failure.
522      */
523     if (program_state.panicking)
524         return;
525
526     if (iflags.toptenwin) {
527         toptenwin = create_nhwindow(NHW_TEXT);
528     }
529
530 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
531 #define HUP if (!program_state.done_hup)
532 #else
533 #define HUP
534 #endif
535
536 #ifdef TOS
537     restore_colors(); /* make sure the screen is black on white */
538 #endif
539     /* create a new 'topten' entry */
540     t0_used = FALSE;
541     t0 = newttentry();
542     t0->ver_major = VERSION_MAJOR;
543     t0->ver_minor = VERSION_MINOR;
544     t0->patchlevel = PATCHLEVEL;
545     t0->points = u.urexp;
546     t0->deathdnum = u.uz.dnum;
547     /* deepest_lev_reached() is in terms of depth(), and reporting the
548      * deepest level reached in the dungeon death occurred in doesn't
549      * seem right, so we have to report the death level in depth() terms
550      * as well (which also seems reasonable since that's all the player
551      * sees on the screen anyway)
552      */
553     t0->deathlev = observable_depth(&u.uz);
554     t0->maxlvl = deepest_lev_reached(TRUE);
555     t0->hp = u.uhp;
556     t0->maxhp = u.uhpmax;
557     t0->deaths = u.umortality;
558     t0->uid = uid;
559     copynchars(t0->plrole, urole.filecode, ROLESZ);
560     copynchars(t0->plrace, urace.filecode, ROLESZ);
561     copynchars(t0->plgend, genders[flags.female].filecode, ROLESZ);
562     copynchars(t0->plalign, aligns[1 - u.ualign.type].filecode, ROLESZ);
563     copynchars(t0->name, plname, NAMSZ);
564     formatkiller(t0->death, sizeof t0->death, how);
565     t0->birthdate = yyyymmdd(ubirthday);
566     t0->deathdate = yyyymmdd(when);
567     t0->tt_next = 0;
568 #if 0 /*C360-19*/
569     urealtime.endtime = when;
570 #endif
571 #ifdef UPDATE_RECORD_IN_PLACE
572     t0->fpos = -1L;
573 #endif
574
575 #ifdef LOGFILE /* used for debugging (who dies of what, where) */
576     if (lock_file(LOGFILE, SCOREPREFIX, 10)) {
577         if (!(lfile = fopen_datafile(LOGFILE, "a", SCOREPREFIX))) {
578             HUP raw_print("Cannot open log file!");
579         } else {
580             writeentry(lfile, t0);
581             (void) fclose(lfile);
582         }
583         unlock_file(LOGFILE);
584     }
585 #endif /* LOGFILE */
586 #ifdef XLOGFILE
587     if (lock_file(XLOGFILE, SCOREPREFIX, 10)) {
588         if (!(xlfile = fopen_datafile(XLOGFILE, "a", SCOREPREFIX))) {
589             HUP raw_print("Cannot open extended log file!");
590         } else {
591             writexlentry(xlfile, t0);
592             (void) fclose(xlfile);
593         }
594         unlock_file(XLOGFILE);
595     }
596 #endif /* XLOGFILE */
597
598     if (wizard || discover) {
599         if (how != PANICKED)
600             HUP {
601                 char pbuf[BUFSZ];
602                 topten_print("");
603                 Sprintf(pbuf,
604 #if 0 /*JP*/
605              "Since you were in %s mode, the score list will not be checked.",
606                         wizard ? "wizard" : "discover");
607 #else
608              "%s\83\82\81[\83h\82Å\83v\83\8c\83C\82µ\82½\82Ì\82Å\83X\83R\83A\83\8a\83X\83g\82É\82Í\8dÚ\82ç\82È\82¢\81D",
609                         wizard ? "\83E\83B\83U\81[\83h" : "\94­\8c©");
610 #endif
611                 topten_print(pbuf);
612             }
613         goto showwin;
614     }
615
616     if (!lock_file(RECORD, SCOREPREFIX, 60))
617         goto destroywin;
618
619 #ifdef UPDATE_RECORD_IN_PLACE
620     rfile = fopen_datafile(RECORD, "r+", SCOREPREFIX);
621 #else
622     rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
623 #endif
624
625     if (!rfile) {
626         HUP raw_print("Cannot open record file!");
627         unlock_file(RECORD);
628         goto destroywin;
629     }
630
631     HUP topten_print("");
632
633     /* assure minimum number of points */
634     if (t0->points < sysopt.pointsmin)
635         t0->points = 0;
636
637     t1 = tt_head = newttentry();
638     tprev = 0;
639     /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
640     for (rank = 1;;) {
641         readentry(rfile, t1);
642         if (t1->points < sysopt.pointsmin)
643             t1->points = 0;
644         if (rank0 < 0 && t1->points < t0->points) {
645             rank0 = rank++;
646             if (tprev == 0)
647                 tt_head = t0;
648             else
649                 tprev->tt_next = t0;
650             t0->tt_next = t1;
651 #ifdef UPDATE_RECORD_IN_PLACE
652             t0->fpos = t1->fpos; /* insert here */
653 #endif
654             t0_used = TRUE;
655             occ_cnt--;
656             flg++; /* ask for a rewrite */
657         } else
658             tprev = t1;
659
660         if (t1->points == 0)
661             break;
662         if ((sysopt.pers_is_uid ? t1->uid == t0->uid
663                                 : strncmp(t1->name, t0->name, NAMSZ) == 0)
664             && !strncmp(t1->plrole, t0->plrole, ROLESZ) && --occ_cnt <= 0) {
665             if (rank0 < 0) {
666                 rank0 = 0;
667                 rank1 = rank;
668                 HUP {
669                     char pbuf[BUFSZ];
670
671                     Sprintf(pbuf,
672 /*JP
673                         "You didn't beat your previous score of %ld points.",
674 */
675                         "\82 \82È\82½\82Í\88È\91O\82Ì%ld\83|\83C\83\93\83g\82Ì\83X\83R\83A\82É\93Í\82©\82È\82©\82Á\82½\81D",
676                             t1->points);
677                     topten_print(pbuf);
678                     topten_print("");
679                 }
680             }
681             if (occ_cnt < 0) {
682                 flg++;
683                 continue;
684             }
685         }
686         if (rank <= sysopt.entrymax) {
687             t1->tt_next = newttentry();
688             t1 = t1->tt_next;
689             rank++;
690         }
691         if (rank > sysopt.entrymax) {
692             t1->points = 0;
693             break;
694         }
695     }
696     if (flg) { /* rewrite record file */
697 #ifdef UPDATE_RECORD_IN_PLACE
698         (void) fseek(rfile, (t0->fpos >= 0 ? t0->fpos : final_fpos),
699                      SEEK_SET);
700 #else
701         (void) fclose(rfile);
702         if (!(rfile = fopen_datafile(RECORD, "w", SCOREPREFIX))) {
703             HUP raw_print("Cannot write record file");
704             unlock_file(RECORD);
705             free_ttlist(tt_head);
706             goto destroywin;
707         }
708 #endif /* UPDATE_RECORD_IN_PLACE */
709         if (!done_stopprint)
710             if (rank0 > 0) {
711                 if (rank0 <= 10) {
712 /*JP
713                     topten_print("You made the top ten list!");
714 */
715                     topten_print("\82 \82È\82½\82Í\83g\83b\83v10\83\8a\83X\83g\82É\8dÚ\82Á\82½\81I");
716                 } else {
717                     char pbuf[BUFSZ];
718
719 #if 0 /*JP*/
720                     Sprintf(pbuf,
721                             "You reached the %d%s place on the top %d list.",
722                             rank0, ordin(rank0), sysopt.entrymax);
723 #else
724                     Sprintf(pbuf,
725                             "\82 \82È\82½\82Í\81C\83g\83b\83v%d\83\8a\83X\83g\82Ì%d\88Ê\82É\8dÚ\82Á\82½\81D",
726                             sysopt.entrymax, rank0);
727 #endif
728                     topten_print(pbuf);
729                 }
730                 topten_print("");
731             }
732     }
733     if (rank0 == 0)
734         rank0 = rank1;
735     if (rank0 <= 0)
736         rank0 = rank;
737     if (!done_stopprint)
738         outheader();
739     t1 = tt_head;
740     for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
741         if (flg
742 #ifdef UPDATE_RECORD_IN_PLACE
743             && rank >= rank0
744 #endif
745             )
746             writeentry(rfile, t1);
747         if (done_stopprint)
748             continue;
749         if (rank > flags.end_top && (rank < rank0 - flags.end_around
750                                      || rank > rank0 + flags.end_around)
751             && (!flags.end_own
752                 || (sysopt.pers_is_uid
753                         ? t1->uid == t0->uid
754                         : strncmp(t1->name, t0->name, NAMSZ) == 0)))
755             continue;
756         if (rank == rank0 - flags.end_around
757             && rank0 > flags.end_top + flags.end_around + 1 && !flags.end_own)
758             topten_print("");
759         if (rank != rank0)
760             outentry(rank, t1, FALSE);
761         else if (!rank1)
762             outentry(rank, t1, TRUE);
763         else {
764             outentry(rank, t1, TRUE);
765             outentry(0, t0, TRUE);
766         }
767     }
768     if (rank0 >= rank)
769         if (!done_stopprint)
770             outentry(0, t0, TRUE);
771 #ifdef UPDATE_RECORD_IN_PLACE
772     if (flg) {
773 #ifdef TRUNCATE_FILE
774         /* if a reasonable way to truncate a file exists, use it */
775         truncate_file(rfile);
776 #else
777         /* use sentinel record rather than relying on truncation */
778         t1->points = 0L; /* terminates file when read back in */
779         t1->ver_major = t1->ver_minor = t1->patchlevel = 0;
780         t1->uid = t1->deathdnum = t1->deathlev = 0;
781         t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0;
782         t1->plrole[0] = t1->plrace[0] = t1->plgend[0] = t1->plalign[0] = '-';
783         t1->plrole[1] = t1->plrace[1] = t1->plgend[1] = t1->plalign[1] = 0;
784         t1->birthdate = t1->deathdate = yyyymmdd((time_t) 0L);
785         Strcpy(t1->name, "@");
786         Strcpy(t1->death, "<eod>\n");
787         writeentry(rfile, t1);
788         (void) fflush(rfile);
789 #endif /* TRUNCATE_FILE */
790     }
791 #endif /* UPDATE_RECORD_IN_PLACE */
792     (void) fclose(rfile);
793     unlock_file(RECORD);
794     free_ttlist(tt_head);
795
796 showwin:
797     if (iflags.toptenwin && !done_stopprint)
798         display_nhwindow(toptenwin, 1);
799 destroywin:
800     if (!t0_used)
801         dealloc_ttentry(t0);
802     if (iflags.toptenwin) {
803         destroy_nhwindow(toptenwin);
804         toptenwin = WIN_ERR;
805     }
806 }
807
808 STATIC_OVL void
809 outheader()
810 {
811     char linebuf[BUFSZ];
812     register char *bp;
813
814     Strcpy(linebuf, " No  Points     Name");
815     bp = eos(linebuf);
816     while (bp < linebuf + COLNO - 9)
817         *bp++ = ' ';
818     Strcpy(bp, "Hp [max]");
819     topten_print(linebuf);
820 }
821
822 /* so>0: standout line; so=0: ordinary line */
823 STATIC_OVL void
824 outentry(rank, t1, so)
825 struct toptenentry *t1;
826 int rank;
827 boolean so;
828 {
829     boolean second_line = TRUE;
830     char linebuf[BUFSZ];
831 #if 0 /*JP*/
832     char *bp, hpbuf[24], linebuf3[BUFSZ];
833 #else
834     char *bp, hpbuf[24];
835 #endif
836     int hppos, lngr;
837 #if 1 /*JP*/
838     char who[BUFSZ];
839     char where[BUFSZ];
840     char action[BUFSZ];
841     char car[BUFSZ];
842     char cdr[BUFSZ];
843     const char *jdeath;
844 #endif
845
846 #if 1 /*JP*/
847     who[0] = '\0';
848     where[0] = '\0';
849     action[0] = '\0';
850 #endif
851     linebuf[0] = '\0';
852     if (rank)
853         Sprintf(eos(linebuf), "%3d", rank);
854     else
855         Strcat(linebuf, "   ");
856
857     Sprintf(eos(linebuf), " %10ld  %.10s", t1->points ? t1->points : u.urexp,
858             t1->name);
859     Sprintf(eos(linebuf), "-%s", t1->plrole);
860     if (t1->plrace[0] != '?')
861         Sprintf(eos(linebuf), "-%s", t1->plrace);
862     /* Printing of gender and alignment is intentional.  It has been
863      * part of the NetHack Geek Code, and illustrates a proper way to
864      * specify a character from the command line.
865      */
866     Sprintf(eos(linebuf), "-%s", t1->plgend);
867     if (t1->plalign[0] != '?')
868 /*JP
869         Sprintf(eos(linebuf), "-%s ", t1->plalign);
870 */
871         Sprintf(eos(linebuf), "-%s", t1->plalign);
872     else
873 /*JP
874         Strcat(linebuf, " ");
875 */
876         Strcat(linebuf, "");
877 #if 1 /*JP*/
878         Strcat(linebuf, "\82Í");
879 /*JP: \93ú\96{\8cê\82Å\82Í\81u\81\9b\81\9b\82ð\8eè\82É\81v\82ð\90æ\82É\92Ç\89Á\82µ\82È\82¢\82Æ\95s\8e©\91R */
880         jdeath = t1->death;
881         if (!strncmp(jdeath, "\96\82\8f\9c\82¯\82ð\8eè\82É", 12))
882             jdeath += 12;
883         else if (!strncmp(jdeath, "\93V\8fã\82Å\92p\90J\82ð\8eó\82¯", 16))
884             jdeath += 16;
885         else if (!strncmp(jdeath, "\8bU\95¨\82Ì\96\82\8f\9c\82¯\82ð\92Í\82Ü\82³\82ê", 24))
886             jdeath += 24;
887 #endif
888 #if 0 /*JP*/
889     if (!strncmp("escaped", t1->death, 7)) {
890 #else
891     if (!strncmp("\92E\8fo\82µ\82½", jdeath, 8)
892         || !strncmp("escaped", jdeath, 7)) {
893 #endif
894 #if 0 /*JP*/
895         Sprintf(eos(linebuf), "escaped the dungeon %s[max level %d]",
896                 !strncmp(" (", t1->death + 7, 2) ? t1->death + 7 + 2 : "",
897                 t1->maxlvl);
898         /* fixup for closing paren in "escaped... with...Amulet)[max..." */
899         if ((bp = index(linebuf, ')')) != 0)
900             *bp = (t1->deathdnum == astral_level.dnum) ? '\0' : ' ';
901 #else
902         char jbuf[BUFSZ];
903         strncpy(jbuf, t1->death, jdeath - t1->death);
904         jbuf[jdeath - t1->death] = '\0';
905         Sprintf(action, "%s\96À\8b{\82©\82ç\92E\8fo\82µ\82½[\8dÅ\91å\92n\89º%d\8aK]",
906                 jbuf, t1->maxlvl);
907 #endif
908         second_line = FALSE;
909 #if 0 /*JP*/
910     } else if (!strncmp("ascended", t1->death, 8)) {
911 #else
912     } else if (!strncmp("\8f¸\93V\82µ\82½", jdeath, 8)
913                || !strncmp("ascended", jdeath, 8)) {
914 #endif
915 #if 0 /*JP:T*/
916         Sprintf(eos(linebuf), "ascended to demigod%s-hood",
917                 (t1->plgend[0] == 'F') ? "dess" : "");
918 #else
919         Sprintf(action, "\8f¸\93V\82µ%s\90_\82Æ\82È\82Á\82½",
920                 (t1->plgend[0] == 'F') ? "\8f\97" : "");
921 #endif
922         second_line = FALSE;
923     } else {
924 /*JP
925         if (!strncmp(t1->death, "quit", 4)) {
926 */
927         if (!strncmp(jdeath, "\94²\82¯\82½", 4)) {
928 #if 0 /*JP*/
929             Strcat(linebuf, "quit");
930 #else
931             Strcat(action, t1->death);
932 #endif
933             second_line = FALSE;
934 #if 1 /*JP*/
935         }
936 #else
937         } else if (!strncmp(t1->death, "died of st", 10)) {
938             Strcat(linebuf, "starved to death");
939             second_line = FALSE;
940         } else if (!strncmp(t1->death, "choked", 6)) {
941             Sprintf(eos(linebuf), "choked on h%s food",
942                     (t1->plgend[0] == 'F') ? "er" : "is");
943         } else if (!strncmp(t1->death, "poisoned", 8)) {
944             Strcat(linebuf, "was poisoned");
945         } else if (!strncmp(t1->death, "crushed", 7)) {
946             Strcat(linebuf, "was crushed to death");
947         } else if (!strncmp(t1->death, "petrified by ", 13)) {
948             Strcat(linebuf, "turned to stone");
949         } else
950             Strcat(linebuf, "died");
951 #endif /*JP*/
952
953         if (t1->deathdnum == astral_level.dnum) {
954             const char *arg, *fmt = " on the Plane of %s";
955
956             switch (t1->deathlev) {
957             case -5:
958 #if 0 /*JP*/
959                 fmt = " on the %s Plane";
960 #endif
961 /*JP
962                 arg = "Astral";
963 */
964                 arg = "\93V\8fã\8aE";
965                 break;
966             case -4:
967 /*JP
968                 arg = "Water";
969 */
970                 arg = "\90\85\82Ì\90¸\97ì\8aE";
971                 break;
972             case -3:
973 /*JP
974                 arg = "Fire";
975 */
976                 arg = "\89Î\82Ì\90¸\97ì\8aE";
977                 break;
978             case -2:
979 /*JP
980                 arg = "Air";
981 */
982                 arg = "\95\97\82Ì\90¸\97ì\8aE";
983                 break;
984             case -1:
985 /*JP
986                 arg = "Earth";
987 */
988                 arg = "\92n\82Ì\90¸\97ì\8aE";
989                 break;
990             default:
991                 arg = "Void";
992                 break;
993             }
994 #if 0 /*JP*/
995             Sprintf(eos(linebuf), fmt, arg);
996 #else
997             Sprintf(where, "%s\82É\82Ä", arg);
998 #endif
999         } else {
1000 /*JP
1001             Sprintf(eos(linebuf), " in %s", dungeons[t1->deathdnum].dname);
1002 */
1003             Sprintf(eos(linebuf), "%s", dungeons[t1->deathdnum].dname);
1004             if (t1->deathdnum != knox_level.dnum)
1005 /*JP
1006                 Sprintf(eos(linebuf), " on level %d", t1->deathlev);
1007 */
1008                 Sprintf(eos(linebuf), "\82Ì\92n\89º%d\8aK\82É\82Ä", t1->deathlev);
1009             if (t1->deathlev != t1->maxlvl)
1010 /*JP
1011                 Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
1012 */
1013                 Sprintf(eos(where), "[\8dÅ\91å\92n\89º%d\8aK]", t1->maxlvl);
1014         }
1015
1016         /* kludge for "quit while already on Charon's boat" */
1017         if (!strncmp(t1->death, "quit ", 5))
1018             Strcat(linebuf, t1->death + 4);
1019     }
1020 #if 0 /*JP*/
1021     Strcat(linebuf, ".");
1022 #endif
1023
1024     /* Quit, starved, ascended, and escaped contain no second line */
1025     if (second_line)
1026 /*JP
1027         Sprintf(eos(linebuf), "  %c%s.", highc(*(t1->death)), t1->death + 1);
1028 */
1029         Sprintf(action, "%s", t1->death);
1030
1031 #if 1 /*JP*/
1032     Sprintf(eos(linebuf), "%s%s%s\81D", who, where, action);
1033 #endif
1034     lngr = (int) strlen(linebuf);
1035     if (t1->hp <= 0)
1036         hpbuf[0] = '-', hpbuf[1] = '\0';
1037     else
1038         Sprintf(hpbuf, "%d", t1->hp);
1039     /* beginning of hp column after padding (not actually padded yet) */
1040     hppos = COLNO - (sizeof("  Hp [max]") - 1); /* sizeof(str) includes \0 */
1041 #if 1 /*JP*/
1042     while(lngr >= hppos ){
1043 /*JP hppos\82æ\82è\91O\82Ì\93K\93\96\82È\88Ê\92u\82Å\95ª\8a\84\82·\82é\81D*/
1044         car[0] = '\0';
1045         cdr[0] = '\0';
1046         split_japanese(linebuf, car, cdr, hppos);
1047         
1048         bp = eos(car);
1049         if (so) {
1050             while (bp < car + (COLNO-1)) *bp++ = ' ';
1051             *bp = 0;
1052             topten_print_bold(car);
1053         } else
1054             topten_print(car);
1055         
1056             Sprintf(linebuf, "%15s %s", "", cdr);
1057         lngr = (int)strlen(linebuf);
1058     }
1059 /*JP: \93ú\96{\8cê\82ª\93ü\82é\82Æ\95\8e\9a\97ñ\82ð\8cã\82©\82ç\8c©\82Ä\82¢\82­\82±\82Æ\82Í\82Å\82«\82È\82¢\82½\82ß\83R\83\81\83\93\83g\83A\83E\83g*/
1060 #else
1061     while (lngr >= hppos) {
1062         for (bp = eos(linebuf); !(*bp == ' ' && (bp - linebuf < hppos)); bp--)
1063             ;
1064         /* special case: word is too long, wrap in the middle */
1065         if (linebuf + 15 >= bp)
1066             bp = linebuf + hppos - 1;
1067         /* special case: if about to wrap in the middle of maximum
1068            dungeon depth reached, wrap in front of it instead */
1069         if (bp > linebuf + 5 && !strncmp(bp - 5, " [max", 5))
1070             bp -= 5;
1071         if (*bp != ' ')
1072             Strcpy(linebuf3, bp);
1073         else
1074             Strcpy(linebuf3, bp + 1);
1075         *bp = 0;
1076         if (so) {
1077             while (bp < linebuf + (COLNO - 1))
1078                 *bp++ = ' ';
1079             *bp = 0;
1080             topten_print_bold(linebuf);
1081         } else
1082             topten_print(linebuf);
1083         Sprintf(linebuf, "%15s %s", "", linebuf3);
1084         lngr = strlen(linebuf);
1085     }
1086 #endif /*JP*/
1087     /* beginning of hp column not including padding */
1088     hppos = COLNO - 7 - (int) strlen(hpbuf);
1089     bp = eos(linebuf);
1090
1091     if (bp <= linebuf + hppos) {
1092         /* pad any necessary blanks to the hit point entry */
1093         while (bp < linebuf + hppos)
1094             *bp++ = ' ';
1095         Strcpy(bp, hpbuf);
1096         Sprintf(eos(bp), " %s[%d]",
1097                 (t1->maxhp < 10) ? "  " : (t1->maxhp < 100) ? " " : "",
1098                 t1->maxhp);
1099     }
1100
1101     if (so) {
1102         bp = eos(linebuf);
1103         if (so >= COLNO)
1104             so = COLNO - 1;
1105         while (bp < linebuf + so)
1106             *bp++ = ' ';
1107         *bp = 0;
1108         topten_print_bold(linebuf);
1109     } else
1110         topten_print(linebuf);
1111 }
1112
1113 STATIC_OVL int
1114 score_wanted(current_ver, rank, t1, playerct, players, uid)
1115 boolean current_ver;
1116 int rank;
1117 struct toptenentry *t1;
1118 int playerct;
1119 const char **players;
1120 int uid;
1121 {
1122     int i;
1123
1124     if (current_ver
1125         && (t1->ver_major != VERSION_MAJOR || t1->ver_minor != VERSION_MINOR
1126             || t1->patchlevel != PATCHLEVEL))
1127         return 0;
1128
1129     if (sysopt.pers_is_uid && !playerct && t1->uid == uid)
1130         return 1;
1131
1132     for (i = 0; i < playerct; i++) {
1133         if (players[i][0] == '-' && index("pr", players[i][1])
1134             && players[i][2] == 0 && i + 1 < playerct) {
1135             const char *arg = players[i + 1];
1136             if ((players[i][1] == 'p'
1137                  && str2role(arg) == str2role(t1->plrole))
1138                 || (players[i][1] == 'r'
1139                     && str2race(arg) == str2race(t1->plrace)))
1140                 return 1;
1141             i++;
1142         } else if (strcmp(players[i], "all") == 0
1143                    || strncmp(t1->name, players[i], NAMSZ) == 0
1144                    || (players[i][0] == '-' && players[i][1] == t1->plrole[0]
1145                        && players[i][2] == 0)
1146                    || (digit(players[i][0]) && rank <= atoi(players[i])))
1147             return 1;
1148     }
1149     return 0;
1150 }
1151
1152 /*
1153  * print selected parts of score list.
1154  * argc >= 2, with argv[0] untrustworthy (directory names, et al.),
1155  * and argv[1] starting with "-s".
1156  */
1157 void
1158 prscore(argc, argv)
1159 int argc;
1160 char **argv;
1161 {
1162     const char **players;
1163     int playerct, rank;
1164     boolean current_ver = TRUE, init_done = FALSE;
1165     register struct toptenentry *t1;
1166     FILE *rfile;
1167     boolean match_found = FALSE;
1168     register int i;
1169     char pbuf[BUFSZ];
1170     int uid = -1;
1171     const char *player0;
1172
1173     if (argc < 2 || strncmp(argv[1], "-s", 2)) {
1174         raw_printf("prscore: bad arguments (%d)", argc);
1175         return;
1176     }
1177
1178     rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
1179     if (!rfile) {
1180         raw_print("Cannot open record file!");
1181         return;
1182     }
1183
1184 #ifdef AMIGA
1185     {
1186         extern winid amii_rawprwin;
1187
1188         init_nhwindows(&argc, argv);
1189         amii_rawprwin = create_nhwindow(NHW_TEXT);
1190     }
1191 #endif
1192
1193     /* If the score list isn't after a game, we never went through
1194      * initialization. */
1195     if (wiz1_level.dlevel == 0) {
1196         dlb_init();
1197         init_dungeons();
1198         init_done = TRUE;
1199     }
1200
1201     if (!argv[1][2]) { /* plain "-s" */
1202         argc--;
1203         argv++;
1204     } else
1205         argv[1] += 2;
1206
1207     if (argc > 1 && !strcmp(argv[1], "-v")) {
1208         current_ver = FALSE;
1209         argc--;
1210         argv++;
1211     }
1212
1213     if (argc <= 1) {
1214         if (sysopt.pers_is_uid) {
1215             uid = getuid();
1216             playerct = 0;
1217             players = (const char **) 0;
1218         } else {
1219             player0 = plname;
1220             if (!*player0)
1221 #ifdef AMIGA
1222                 player0 = "all"; /* single user system */
1223 #else
1224                 player0 = "hackplayer";
1225 #endif
1226             playerct = 1;
1227             players = &player0;
1228         }
1229     } else {
1230         playerct = --argc;
1231         players = (const char **) ++argv;
1232     }
1233     raw_print("");
1234
1235     t1 = tt_head = newttentry();
1236     for (rank = 1;; rank++) {
1237         readentry(rfile, t1);
1238         if (t1->points == 0)
1239             break;
1240         if (!match_found
1241             && score_wanted(current_ver, rank, t1, playerct, players, uid))
1242             match_found = TRUE;
1243         t1->tt_next = newttentry();
1244         t1 = t1->tt_next;
1245     }
1246
1247     (void) fclose(rfile);
1248     if (init_done) {
1249         free_dungeons();
1250         dlb_cleanup();
1251     }
1252
1253     if (match_found) {
1254         outheader();
1255         t1 = tt_head;
1256         for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
1257             if (score_wanted(current_ver, rank, t1, playerct, players, uid))
1258                 (void) outentry(rank, t1, FALSE);
1259         }
1260     } else {
1261         Sprintf(pbuf, "Cannot find any %sentries for ",
1262                 current_ver ? "current " : "");
1263         if (playerct < 1)
1264             Strcat(pbuf, "you.");
1265         else {
1266             if (playerct > 1)
1267                 Strcat(pbuf, "any of ");
1268             for (i = 0; i < playerct; i++) {
1269                 /* stop printing players if there are too many to fit */
1270                 if (strlen(pbuf) + strlen(players[i]) + 2 >= BUFSZ) {
1271                     if (strlen(pbuf) < BUFSZ - 4)
1272                         Strcat(pbuf, "...");
1273                     else
1274                         Strcpy(pbuf + strlen(pbuf) - 4, "...");
1275                     break;
1276                 }
1277                 Strcat(pbuf, players[i]);
1278                 if (i < playerct - 1) {
1279                     if (players[i][0] == '-' && index("pr", players[i][1])
1280                         && players[i][2] == 0)
1281                         Strcat(pbuf, " ");
1282                     else
1283                         Strcat(pbuf, ":");
1284                 }
1285             }
1286         }
1287         raw_print(pbuf);
1288         raw_printf("Usage: %s -s [-v] <playertypes> [maxrank] [playernames]",
1289
1290                    hname);
1291         raw_printf("Player types are: [-p role] [-r race]");
1292     }
1293     free_ttlist(tt_head);
1294 #ifdef AMIGA
1295     {
1296         extern winid amii_rawprwin;
1297
1298         display_nhwindow(amii_rawprwin, 1);
1299         destroy_nhwindow(amii_rawprwin);
1300         amii_rawprwin = WIN_ERR;
1301     }
1302 #endif
1303 }
1304
1305 STATIC_OVL int
1306 classmon(plch, fem)
1307 char *plch;
1308 boolean fem;
1309 {
1310     int i;
1311
1312     /* Look for this role in the role table */
1313     for (i = 0; roles[i].name.m; i++)
1314         if (!strncmp(plch, roles[i].filecode, ROLESZ)) {
1315             if (fem && roles[i].femalenum != NON_PM)
1316                 return roles[i].femalenum;
1317             else if (roles[i].malenum != NON_PM)
1318                 return roles[i].malenum;
1319             else
1320                 return PM_HUMAN;
1321         }
1322     /* this might be from a 3.2.x score for former Elf class */
1323     if (!strcmp(plch, "E"))
1324         return PM_RANGER;
1325
1326     impossible("What weird role is this? (%s)", plch);
1327     return  PM_HUMAN_MUMMY;
1328 }
1329
1330 /*
1331  * Get a random player name and class from the high score list,
1332  * and attach them to an object (for statues or morgue corpses).
1333  */
1334 struct obj *
1335 tt_oname(otmp)
1336 struct obj *otmp;
1337 {
1338     int rank;
1339     register int i;
1340     register struct toptenentry *tt;
1341     FILE *rfile;
1342     struct toptenentry tt_buf;
1343
1344     if (!otmp)
1345         return (struct obj *) 0;
1346
1347     rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
1348     if (!rfile) {
1349         impossible("Cannot open record file!");
1350         return (struct obj *) 0;
1351     }
1352
1353     tt = &tt_buf;
1354     rank = rnd(sysopt.tt_oname_maxrank);
1355 pickentry:
1356     for (i = rank; i; i--) {
1357         readentry(rfile, tt);
1358         if (tt->points == 0)
1359             break;
1360     }
1361
1362     if (tt->points == 0) {
1363         if (rank > 1) {
1364             rank = 1;
1365             rewind(rfile);
1366             goto pickentry;
1367         }
1368         otmp = (struct obj *) 0;
1369     } else {
1370         set_corpsenm(otmp, classmon(tt->plrole, (tt->plgend[0] == 'F')));
1371         otmp = oname(otmp, tt->name);
1372     }
1373
1374     (void) fclose(rfile);
1375     return otmp;
1376 }
1377
1378 #ifdef NO_SCAN_BRACK
1379 /* Lattice scanf isn't up to reading the scorefile.  What */
1380 /* follows deals with that; I admit it's ugly. (KL) */
1381 /* Now generally available (KL) */
1382 STATIC_OVL void
1383 nsb_mung_line(p)
1384 char *p;
1385 {
1386     while ((p = index(p, ' ')) != 0)
1387         *p = '|';
1388 }
1389
1390 STATIC_OVL void
1391 nsb_unmung_line(p)
1392 char *p;
1393 {
1394     while ((p = index(p, '|')) != 0)
1395         *p = ' ';
1396 }
1397 #endif /* NO_SCAN_BRACK */
1398
1399 /*topten.c*/