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. */
10 #include "patchlevel.h"
14 /* We don't want to rewrite the whole file, because that entails
15 creating a new version which requires that the old one be deletable. */
16 #define UPDATE_RECORD_IN_PLACE
20 * Updating in place can leave junk at the end of the file in some
21 * circumstances (if it shrinks and the O.S. doesn't have a straightforward
22 * way to truncate it). The trailing junk is harmless and the code
23 * which reads the scores will ignore it.
25 #ifdef UPDATE_RECORD_IN_PLACE
26 static long final_fpos;
29 #define done_stopprint program_state.stopprint
31 #define newttentry() (struct toptenentry *) alloc(sizeof (struct toptenentry))
32 #define dealloc_ttentry(ttent) free((genericptr_t) (ttent))
38 struct toptenentry *tt_next;
39 #ifdef UPDATE_RECORD_IN_PLACE
43 int deathdnum, deathlev;
44 int maxlvl, hp, maxhp, deaths;
45 int ver_major, ver_minor, patchlevel;
46 long deathdate, birthdate;
48 char plrole[ROLESZ + 1];
49 char plrace[ROLESZ + 1];
50 char plgend[ROLESZ + 1];
51 char plalign[ROLESZ + 1];
53 char death[DTHSZ + 1];
55 /* size big enough to read in all the string fields at once; includes
56 room for separating space or trailing newline plus string terminator */
57 #define SCANBUFSZ (4 * (ROLESZ + 1) + (NAMSZ + 1) + (DTHSZ + 1) + 1)
59 STATIC_DCL void FDECL(topten_print, (const char *));
60 STATIC_DCL void FDECL(topten_print_bold, (const char *));
61 STATIC_DCL xchar FDECL(observable_depth, (d_level *));
62 STATIC_DCL void NDECL(outheader);
63 STATIC_DCL void FDECL(outentry, (int, struct toptenentry *, BOOLEAN_P));
64 STATIC_DCL void FDECL(discardexcess, (FILE *));
65 STATIC_DCL void FDECL(readentry, (FILE *, struct toptenentry *));
66 STATIC_DCL void FDECL(writeentry, (FILE *, struct toptenentry *));
67 STATIC_DCL void FDECL(writexlentry, (FILE *, struct toptenentry *));
68 STATIC_DCL long NDECL(encodexlogflags);
69 STATIC_DCL long NDECL(encodeconduct);
70 STATIC_DCL long NDECL(encodeachieve);
71 STATIC_DCL void FDECL(free_ttlist, (struct toptenentry *));
72 STATIC_DCL int FDECL(classmon, (char *, BOOLEAN_P));
73 STATIC_DCL int FDECL(score_wanted, (BOOLEAN_P, int, struct toptenentry *, int,
76 STATIC_DCL void FDECL(nsb_mung_line, (char *));
77 STATIC_DCL void FDECL(nsb_unmung_line, (char *));
80 static winid toptenwin = WIN_ERR;
82 /* "killed by",&c ["an"] 'killer.name' */
84 formatkiller(buf, siz, how)
89 static NEARDATA const char *const killed_by_prefix[] = {
90 /* DIED, CHOKING, POISONING, STARVING, */
92 "killed by ", "choked on ", "poisoned by ", "died of ",
94 "
\8e\80\82ñ
\82¾", "
\82Å
\92\82\91§
\82µ
\82½", "
\82Ì
\93Å
\82Å
\8e\80\82ñ
\82¾", "",
95 /* DROWNING, BURNING, DISSOLVED, CRUSHING, */
97 "drowned in ", "burned by ", "dissolved in ", "crushed to death by ",
99 "
\93M
\8e\80\82µ
\82½","
\8fÄ
\8e\80\82µ
\82½", "
\97n
\8aâ
\82É
\97n
\82¯
\82½", "
\89\9f\82µ
\92×
\82³
\82ê
\82½",
100 /* STONING, TURNED_SLIME, GENOCIDED, */
102 "petrified by ", "turned to slime by ", "killed by ",
104 "
\90Î
\82É
\82È
\82Á
\82½", "
\82É
\83X
\83\89\83C
\83\80\82É
\82³
\82ê
\82½", "
\8bs
\8eE
\82³
\82ê
\82½",
105 /* PANICKED, TRICKED, QUIT, ESCAPED, ASCENDED */
109 char *kname = killer.name;
111 buf[0] = '\0'; /* so strncat() can find the end */
112 #if 1 /*JP*//*
\90æ
\82É
\91Î
\8fÛ
\82ð
\83R
\83s
\81[*/
113 strncat(buf, kname, siz - 1);
116 switch (killer.format) {
118 impossible("bad killer format? (%d)", killer.format);
120 case NO_KILLER_PREFIX:
123 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\95s
\97v*/
129 (void) strncat(buf, killed_by_prefix[how], siz - 1);
132 #else /*JP:
\8aù
\82É
\91Î
\8fÛ
\82ð
\83R
\83s
\81[
\82µ
\82Ä
\82¢
\82é
\82Ì
\82Å
\92P
\82É
\92Ç
\89Á*/
133 (void) strncat(buf, killed_by_prefix[how], siz - 1);
138 (void) strncat(buf, "
\82É
\8eE
\82³
\82ê
\82½", siz - 1);
141 #if 0 /*JP*//*
\8aù
\82É
\83R
\83s
\81[
\8dÏ
\82Ý*/
142 /* we're writing into buf[0] (after possibly advancing buf) rather than
143 appending, but strncat() appends a terminator and strncpy() doesn't */
144 (void) strncat(buf, kname, siz - 1);
152 if (toptenwin == WIN_ERR)
155 putstr(toptenwin, ATR_NONE, x);
162 if (toptenwin == WIN_ERR)
165 putstr(toptenwin, ATR_BOLD, x);
169 observable_depth(lev)
173 /* if we ever randomize the order of the elemental planes, we
174 must use a constant external representation in the record file */
175 if (In_endgame(lev)) {
176 if (Is_astralevel(lev))
178 else if (Is_waterlevel(lev))
180 else if (Is_firelevel(lev))
182 else if (Is_airlevel(lev))
184 else if (Is_earthlevel(lev))
193 /* throw away characters until current record has been entirely consumed */
202 } while (c != '\n' && c != EOF);
208 struct toptenentry *tt;
210 char inbuf[SCANBUFSZ], s1[SCANBUFSZ], s2[SCANBUFSZ], s3[SCANBUFSZ],
211 s4[SCANBUFSZ], s5[SCANBUFSZ], s6[SCANBUFSZ];
213 #ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
214 static const char fmt[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c";
215 static const char fmt32[] = "%c%c %s %s%*c";
216 static const char fmt33[] = "%s %s %s %s %s %s%*c";
218 static const char fmt[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
219 static const char fmt32[] = "%c%c %[^,],%[^\n]%*c";
220 static const char fmt33[] = "%s %s %s %s %[^,],%[^\n]%*c";
223 #ifdef UPDATE_RECORD_IN_PLACE
224 /* note: input below must read the record's terminating newline */
225 final_fpos = tt->fpos = ftell(rfile);
228 if (fscanf(rfile, fmt, &tt->ver_major, &tt->ver_minor, &tt->patchlevel,
229 &tt->points, &tt->deathdnum, &tt->deathlev, &tt->maxlvl,
230 &tt->hp, &tt->maxhp, &tt->deaths, &tt->deathdate,
231 &tt->birthdate, &tt->uid) != TTFIELDS) {
234 discardexcess(rfile);
236 /* load remainder of record into a local buffer;
237 this imposes an implicit length limit of SCANBUFSZ
238 on every string field extracted from the buffer */
239 if (!fgets(inbuf, sizeof inbuf, rfile)) {
240 /* sscanf will fail and tt->points will be set to 0 */
242 } else if (!index(inbuf, '\n')) {
243 Strcpy(&inbuf[sizeof inbuf - 2], "\n");
244 discardexcess(rfile);
246 /* Check for backwards compatibility */
247 if (tt->ver_major < 3 || (tt->ver_major == 3 && tt->ver_minor < 3)) {
250 if (sscanf(inbuf, fmt32, tt->plrole, tt->plgend, s1, s2) == 4) {
251 tt->plrole[1] = tt->plgend[1] = '\0'; /* read via %c */
252 copynchars(tt->name, s1, (int) (sizeof tt->name) - 1);
253 copynchars(tt->death, s2, (int) (sizeof tt->death) - 1);
256 tt->plrole[1] = '\0';
257 if ((i = str2role(tt->plrole)) >= 0)
258 Strcpy(tt->plrole, roles[i].filecode);
259 Strcpy(tt->plrace, "?");
260 Strcpy(tt->plgend, (tt->plgend[0] == 'M') ? "Mal" : "Fem");
261 Strcpy(tt->plalign, "?");
262 } else if (sscanf(inbuf, fmt33, s1, s2, s3, s4, s5, s6) == 6) {
263 copynchars(tt->plrole, s1, (int) (sizeof tt->plrole) - 1);
264 copynchars(tt->plrace, s2, (int) (sizeof tt->plrace) - 1);
265 copynchars(tt->plgend, s3, (int) (sizeof tt->plgend) - 1);
266 copynchars(tt->plalign, s4, (int) (sizeof tt->plalign) - 1);
267 copynchars(tt->name, s5, (int) (sizeof tt->name) - 1);
268 copynchars(tt->death, s6, (int) (sizeof tt->death) - 1);
272 if (tt->points > 0) {
273 nsb_unmung_line(tt->name);
274 nsb_unmung_line(tt->death);
279 /* check old score entries for Y2K problem and fix whenever found */
280 if (tt->points > 0) {
281 if (tt->birthdate < 19000000L)
282 tt->birthdate += 19000000L;
283 if (tt->deathdate < 19000000L)
284 tt->deathdate += 19000000L;
289 writeentry(rfile, tt)
291 struct toptenentry *tt;
293 static const char fmt32[] = "%c%c "; /* role,gender */
294 static const char fmt33[] = "%s %s %s %s "; /* role,race,gndr,algn */
295 #ifndef NO_SCAN_BRACK
296 static const char fmt0[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
297 static const char fmtX[] = "%s,%s%s%s\n";
298 #else /* NO_SCAN_BRACK */
299 static const char fmt0[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d ";
300 static const char fmtX[] = "%s %s%s%s\n";
302 nsb_mung_line(tt->name);
303 nsb_mung_line(tt->death);
306 (void) fprintf(rfile, fmt0, tt->ver_major, tt->ver_minor, tt->patchlevel,
307 tt->points, tt->deathdnum, tt->deathlev, tt->maxlvl,
308 tt->hp, tt->maxhp, tt->deaths, tt->deathdate,
309 tt->birthdate, tt->uid);
310 if (tt->ver_major < 3 || (tt->ver_major == 3 && tt->ver_minor < 3))
311 (void) fprintf(rfile, fmt32, tt->plrole[0], tt->plgend[0]);
313 (void) fprintf(rfile, fmt33, tt->plrole, tt->plrace, tt->plgend,
315 (void) fprintf(rfile, fmtX, onlyspace(tt->name) ? "_" : tt->name,
317 (multi ? ", while " : ""),
318 (multi ? (multi_reason ? multi_reason : "helpless") : ""));
321 nsb_unmung_line(tt->name);
322 nsb_unmung_line(tt->death);
326 /* as tab is never used in eg. plname or death, no need to mangle those. */
328 writexlentry(rfile, tt)
330 struct toptenentry *tt;
332 #define Fprintf (void) fprintf
333 #define XLOG_SEP '\t' /* xlogfile field separator. */
336 Sprintf(buf, "version=%d.%d.%d", tt->ver_major, tt->ver_minor,
338 Sprintf(eos(buf), "%cpoints=%ld%cdeathdnum=%d%cdeathlev=%d", XLOG_SEP,
339 tt->points, XLOG_SEP, tt->deathdnum, XLOG_SEP, tt->deathlev);
340 Sprintf(eos(buf), "%cmaxlvl=%d%chp=%d%cmaxhp=%d", XLOG_SEP, tt->maxlvl,
341 XLOG_SEP, tt->hp, XLOG_SEP, tt->maxhp);
342 Sprintf(eos(buf), "%cdeaths=%d%cdeathdate=%ld%cbirthdate=%ld%cuid=%d",
343 XLOG_SEP, tt->deaths, XLOG_SEP, tt->deathdate, XLOG_SEP,
344 tt->birthdate, XLOG_SEP, tt->uid);
345 Fprintf(rfile, "%s", buf);
346 Sprintf(buf, "%crole=%s%crace=%s%cgender=%s%calign=%s", XLOG_SEP,
347 tt->plrole, XLOG_SEP, tt->plrace, XLOG_SEP, tt->plgend, XLOG_SEP,
349 Fprintf(rfile, "%s%cname=%s%cdeath=%s",
350 buf, /* (already includes separator) */
351 XLOG_SEP, plname, XLOG_SEP, tt->death);
353 Fprintf(rfile, "%cwhile=%s", XLOG_SEP,
354 multi_reason ? multi_reason : "helpless");
355 Fprintf(rfile, "%cconduct=0x%lx%cturns=%ld%cachieve=0x%lx", XLOG_SEP,
356 encodeconduct(), XLOG_SEP, moves, XLOG_SEP, encodeachieve());
357 Fprintf(rfile, "%crealtime=%ld%cstarttime=%ld%cendtime=%ld", XLOG_SEP,
358 (long) urealtime.realtime, XLOG_SEP,
359 (long) ubirthday, XLOG_SEP, (long) urealtime.finish_time);
360 Fprintf(rfile, "%cgender0=%s%calign0=%s", XLOG_SEP,
361 genders[flags.initgend].filecode, XLOG_SEP,
362 aligns[1 - u.ualignbase[A_ORIGINAL]].filecode);
363 Fprintf(rfile, "%cflags=0x%lx", XLOG_SEP, encodexlogflags());
364 Fprintf(rfile, "\n");
377 if (!u.uroleplay.numbones)
388 if (!u.uconduct.food)
390 if (!u.uconduct.unvegan)
392 if (!u.uconduct.unvegetarian)
394 if (!u.uconduct.gnostic)
396 if (!u.uconduct.weaphit)
398 if (!u.uconduct.killer)
400 if (!u.uconduct.literate)
402 if (!u.uconduct.polypiles)
404 if (!u.uconduct.polyselfs)
406 if (!u.uconduct.wishes)
408 if (!u.uconduct.wisharti)
410 if (!num_genocides())
423 if (u.uachieve.enter_gehennom)
425 if (u.uachieve.menorah)
429 if (u.uevent.invoked)
431 if (u.uachieve.amulet)
433 if (In_endgame(&u.uz))
435 if (Is_astralevel(&u.uz))
437 if (u.uachieve.ascended)
439 if (u.uachieve.mines_luckstone)
441 if (u.uachieve.finish_sokoban)
443 if (u.uachieve.killed_medusa)
445 if (u.uroleplay.blind)
447 if (u.uroleplay.nudist)
455 struct toptenentry *tt;
457 struct toptenentry *ttnext;
459 while (tt->points > 0) {
460 ttnext = tt->tt_next;
473 int rank, rank0 = -1, rank1 = 0;
474 int occ_cnt = sysopt.persmax;
475 register struct toptenentry *t0, *tprev;
476 struct toptenentry *t1;
478 register int flg = 0;
485 #endif /* XLOGFILE */
488 /* Under DICE 3.0, this crashes the system consistently, apparently due to
489 * corruption of *rfile somewhere. Until I figure this out, just cut out
490 * topten support entirely - at least then the game exits cleanly. --AC
495 /* If we are in the midst of a panic, cut out topten entirely.
496 * topten uses alloc() several times, which will lead to
497 * problems if the panic was the result of an alloc() failure.
499 if (program_state.panicking)
502 if (iflags.toptenwin) {
503 toptenwin = create_nhwindow(NHW_TEXT);
506 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
507 #define HUP if (!program_state.done_hup)
513 restore_colors(); /* make sure the screen is black on white */
515 /* create a new 'topten' entry */
518 t0->ver_major = VERSION_MAJOR;
519 t0->ver_minor = VERSION_MINOR;
520 t0->patchlevel = PATCHLEVEL;
521 t0->points = u.urexp;
522 t0->deathdnum = u.uz.dnum;
523 /* deepest_lev_reached() is in terms of depth(), and reporting the
524 * deepest level reached in the dungeon death occurred in doesn't
525 * seem right, so we have to report the death level in depth() terms
526 * as well (which also seems reasonable since that's all the player
527 * sees on the screen anyway)
529 t0->deathlev = observable_depth(&u.uz);
530 t0->maxlvl = deepest_lev_reached(TRUE);
532 t0->maxhp = u.uhpmax;
533 t0->deaths = u.umortality;
535 copynchars(t0->plrole, urole.filecode, ROLESZ);
536 copynchars(t0->plrace, urace.filecode, ROLESZ);
537 copynchars(t0->plgend, genders[flags.female].filecode, ROLESZ);
538 copynchars(t0->plalign, aligns[1 - u.ualign.type].filecode, ROLESZ);
539 copynchars(t0->name, plname, NAMSZ);
540 formatkiller(t0->death, sizeof t0->death, how);
541 t0->birthdate = yyyymmdd(ubirthday);
542 t0->deathdate = yyyymmdd(when);
544 #ifdef UPDATE_RECORD_IN_PLACE
548 #ifdef LOGFILE /* used for debugging (who dies of what, where) */
549 if (lock_file(LOGFILE, SCOREPREFIX, 10)) {
550 if (!(lfile = fopen_datafile(LOGFILE, "a", SCOREPREFIX))) {
551 HUP raw_print("Cannot open log file!");
553 writeentry(lfile, t0);
554 (void) fclose(lfile);
556 unlock_file(LOGFILE);
560 if (lock_file(XLOGFILE, SCOREPREFIX, 10)) {
561 if (!(xlfile = fopen_datafile(XLOGFILE, "a", SCOREPREFIX))) {
562 HUP raw_print("Cannot open extended log file!");
564 writexlentry(xlfile, t0);
565 (void) fclose(xlfile);
567 unlock_file(XLOGFILE);
569 #endif /* XLOGFILE */
571 if (wizard || discover) {
578 "Since you were in %s mode, the score list will not be checked.",
579 wizard ? "wizard" : "discover");
581 "%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",
582 wizard ? "
\83E
\83B
\83U
\81[
\83h" : "
\94
\8c©");
589 if (!lock_file(RECORD, SCOREPREFIX, 60))
592 #ifdef UPDATE_RECORD_IN_PLACE
593 rfile = fopen_datafile(RECORD, "r+", SCOREPREFIX);
595 rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
599 HUP raw_print("Cannot open record file!");
604 HUP topten_print("");
606 /* assure minimum number of points */
607 if (t0->points < sysopt.pointsmin)
610 t1 = tt_head = newttentry();
612 /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
614 readentry(rfile, t1);
615 if (t1->points < sysopt.pointsmin)
617 if (rank0 < 0 && t1->points < t0->points) {
624 #ifdef UPDATE_RECORD_IN_PLACE
625 t0->fpos = t1->fpos; /* insert here */
629 flg++; /* ask for a rewrite */
635 if ((sysopt.pers_is_uid ? t1->uid == t0->uid
636 : strncmp(t1->name, t0->name, NAMSZ) == 0)
637 && !strncmp(t1->plrole, t0->plrole, ROLESZ) && --occ_cnt <= 0) {
646 "You didn't beat your previous score of %ld points.",
648 "
\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",
659 if (rank <= sysopt.entrymax) {
660 t1->tt_next = newttentry();
664 if (rank > sysopt.entrymax) {
669 if (flg) { /* rewrite record file */
670 #ifdef UPDATE_RECORD_IN_PLACE
671 (void) fseek(rfile, (t0->fpos >= 0 ? t0->fpos : final_fpos),
674 (void) fclose(rfile);
675 if (!(rfile = fopen_datafile(RECORD, "w", SCOREPREFIX))) {
676 HUP raw_print("Cannot write record file");
678 free_ttlist(tt_head);
681 #endif /* UPDATE_RECORD_IN_PLACE */
686 topten_print("You made the top ten list!");
688 topten_print("
\82 \82È
\82½
\82Í
\83g
\83b
\83v10
\83\8a\83X
\83g
\82É
\8dÚ
\82Á
\82½
\81I");
694 "You reached the %d%s place on the top %d list.",
695 rank0, ordin(rank0), sysopt.entrymax);
698 "
\82 \82È
\82½
\82Í
\81C
\83g
\83b
\83v%d
\83\8a\83X
\83g
\82Ì%d
\88Ê
\82É
\8dÚ
\82Á
\82½
\81D",
699 sysopt.entrymax, rank0);
713 for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
715 #ifdef UPDATE_RECORD_IN_PLACE
719 writeentry(rfile, t1);
722 if (rank > flags.end_top && (rank < rank0 - flags.end_around
723 || rank > rank0 + flags.end_around)
725 || (sysopt.pers_is_uid
727 : strncmp(t1->name, t0->name, NAMSZ) == 0)))
729 if (rank == rank0 - flags.end_around
730 && rank0 > flags.end_top + flags.end_around + 1 && !flags.end_own)
733 outentry(rank, t1, FALSE);
735 outentry(rank, t1, TRUE);
737 outentry(rank, t1, TRUE);
738 outentry(0, t0, TRUE);
743 outentry(0, t0, TRUE);
744 #ifdef UPDATE_RECORD_IN_PLACE
747 /* if a reasonable way to truncate a file exists, use it */
748 truncate_file(rfile);
750 /* use sentinel record rather than relying on truncation */
751 t1->points = 0L; /* terminates file when read back in */
752 t1->ver_major = t1->ver_minor = t1->patchlevel = 0;
753 t1->uid = t1->deathdnum = t1->deathlev = 0;
754 t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0;
755 t1->plrole[0] = t1->plrace[0] = t1->plgend[0] = t1->plalign[0] = '-';
756 t1->plrole[1] = t1->plrace[1] = t1->plgend[1] = t1->plalign[1] = 0;
757 t1->birthdate = t1->deathdate = yyyymmdd((time_t) 0L);
758 Strcpy(t1->name, "@");
759 Strcpy(t1->death, "<eod>\n");
760 writeentry(rfile, t1);
761 (void) fflush(rfile);
762 #endif /* TRUNCATE_FILE */
764 #endif /* UPDATE_RECORD_IN_PLACE */
765 (void) fclose(rfile);
767 free_ttlist(tt_head);
770 if (iflags.toptenwin && !done_stopprint)
771 display_nhwindow(toptenwin, 1);
775 if (iflags.toptenwin) {
776 destroy_nhwindow(toptenwin);
787 Strcpy(linebuf, " No Points Name");
789 while (bp < linebuf + COLNO - 9)
791 Strcpy(bp, "Hp [max]");
792 topten_print(linebuf);
795 /* so>0: standout line; so=0: ordinary line */
797 outentry(rank, t1, so)
798 struct toptenentry *t1;
802 boolean second_line = TRUE;
804 char *bp, hpbuf[24], linebuf3[BUFSZ];
822 Sprintf(eos(linebuf), "%3d", rank);
824 Strcat(linebuf, " ");
826 Sprintf(eos(linebuf), " %10ld %.10s", t1->points ? t1->points : u.urexp,
828 Sprintf(eos(linebuf), "-%s", t1->plrole);
829 if (t1->plrace[0] != '?')
830 Sprintf(eos(linebuf), "-%s", t1->plrace);
831 /* Printing of gender and alignment is intentional. It has been
832 * part of the NetHack Geek Code, and illustrates a proper way to
833 * specify a character from the command line.
835 Sprintf(eos(linebuf), "-%s", t1->plgend);
836 if (t1->plalign[0] != '?')
838 Sprintf(eos(linebuf), "-%s ", t1->plalign);
840 Sprintf(eos(linebuf), "-%s", t1->plalign);
843 Strcat(linebuf, " ");
847 Strcat(linebuf, "
\82Í");
848 /*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 */
850 if (!strncmp(jdeath, "
\96\82\8f\9c\82¯
\82ð
\8eè
\82É", 12))
852 else if (!strncmp(jdeath, "
\93V
\8fã
\82Å
\92p
\90J
\82ð
\8eó
\82¯", 16))
854 else if (!strncmp(jdeath, "
\8bU
\95¨
\82Ì
\96\82\8f\9c\82¯
\82ð
\92Í
\82Ü
\82³
\82ê", 24))
858 if (!strncmp("escaped", t1->death, 7)) {
859 Sprintf(eos(linebuf), "escaped the dungeon %s[max level %d]",
860 !strncmp(" (", t1->death + 7, 2) ? t1->death + 7 + 2 : "",
862 /* fixup for closing paren in "escaped... with...Amulet)[max..." */
863 if ((bp = index(linebuf, ')')) != 0)
864 *bp = (t1->deathdnum == astral_level.dnum) ? '\0' : ' ';
866 if (!strncmp("
\92E
\8fo
\82µ
\82½", jdeath, 8)
867 || !strncmp("escaped", jdeath, 7)) {
869 strncpy(jbuf, t1->death, jdeath - t1->death);
870 jbuf[jdeath - t1->death] = '\0';
871 Sprintf(action, "%s
\96À
\8b{
\82©
\82ç
\92E
\8fo
\82µ
\82½[
\8dÅ
\91å
\92n
\89º%d
\8aK]",
876 } else if (!strncmp("ascended", t1->death, 8)) {
878 } else if (!strncmp("
\8f¸
\93V
\82µ
\82½", jdeath, 8)
879 || !strncmp("ascended", jdeath, 8)) {
882 Sprintf(eos(linebuf), "ascended to demigod%s-hood",
883 (t1->plgend[0] == 'F') ? "dess" : "");
885 Sprintf(action, "
\8f¸
\93V
\82µ%s
\90_
\82Æ
\82È
\82Á
\82½",
886 (t1->plgend[0] == 'F') ? "
\8f\97" : "");
891 if (!strncmp(t1->death, "quit", 4)) {
893 if (!strncmp(jdeath, "
\94²
\82¯
\82½", 4)) {
895 Strcat(linebuf, "quit");
897 Strcat(action, t1->death);
903 } else if (!strncmp(t1->death, "died of st", 10)) {
904 Strcat(linebuf, "starved to death");
906 } else if (!strncmp(t1->death, "choked", 6)) {
907 Sprintf(eos(linebuf), "choked on h%s food",
908 (t1->plgend[0] == 'F') ? "er" : "is");
909 } else if (!strncmp(t1->death, "poisoned", 8)) {
910 Strcat(linebuf, "was poisoned");
911 } else if (!strncmp(t1->death, "crushed", 7)) {
912 Strcat(linebuf, "was crushed to death");
913 } else if (!strncmp(t1->death, "petrified by ", 13)) {
914 Strcat(linebuf, "turned to stone");
916 Strcat(linebuf, "died");
919 if (t1->deathdnum == astral_level.dnum) {
920 const char *arg, *fmt = " on the Plane of %s";
922 switch (t1->deathlev) {
925 fmt = " on the %s Plane";
930 arg = "
\93V
\8fã
\8aE";
936 arg = "
\90\85\82Ì
\90¸
\97ì
\8aE";
942 arg = "
\89Î
\82Ì
\90¸
\97ì
\8aE";
948 arg = "
\95\97\82Ì
\90¸
\97ì
\8aE";
954 arg = "
\92n
\82Ì
\90¸
\97ì
\8aE";
961 Sprintf(eos(linebuf), fmt, arg);
963 Sprintf(where, "%s
\82É
\82Ä", arg);
967 Sprintf(eos(linebuf), " in %s", dungeons[t1->deathdnum].dname);
969 Sprintf(eos(linebuf), "%s", dungeons[t1->deathdnum].dname);
970 if (t1->deathdnum != knox_level.dnum)
972 Sprintf(eos(linebuf), " on level %d", t1->deathlev);
974 Sprintf(eos(linebuf), "
\82Ì
\92n
\89º%d
\8aK
\82É
\82Ä", t1->deathlev);
975 if (t1->deathlev != t1->maxlvl)
977 Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
979 Sprintf(eos(where), "[
\8dÅ
\91å
\92n
\89º%d
\8aK]", t1->maxlvl);
982 /* kludge for "quit while already on Charon's boat" */
983 if (!strncmp(t1->death, "quit ", 5))
984 Strcat(linebuf, t1->death + 4);
987 Strcat(linebuf, ".");
990 /* Quit, starved, ascended, and escaped contain no second line */
993 Sprintf(eos(linebuf), " %c%s.", highc(*(t1->death)), t1->death + 1);
995 Sprintf(action, "%s", t1->death);
998 Sprintf(eos(linebuf), "%s%s%s
\81D", who, where, action);
1000 lngr = (int) strlen(linebuf);
1002 hpbuf[0] = '-', hpbuf[1] = '\0';
1004 Sprintf(hpbuf, "%d", t1->hp);
1005 /* beginning of hp column after padding (not actually padded yet) */
1006 hppos = COLNO - (sizeof(" Hp [max]") - 1); /* sizeof(str) includes \0 */
1008 while(lngr >= hppos ){
1009 /*JP hppos
\82æ
\82è
\91O
\82Ì
\93K
\93\96\82È
\88Ê
\92u
\82Å
\95ª
\8a\84\82·
\82é
\81D*/
1012 split_japanese(linebuf, car, cdr, hppos);
1016 while (bp < car + (COLNO-1)) *bp++ = ' ';
1018 topten_print_bold(car);
1022 Sprintf(linebuf, "%15s %s", "", cdr);
1023 lngr = (int)strlen(linebuf);
1025 /*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*/
1027 while (lngr >= hppos) {
1028 for (bp = eos(linebuf); !(*bp == ' ' && (bp - linebuf < hppos)); bp--)
1030 /* special case: word is too long, wrap in the middle */
1031 if (linebuf + 15 >= bp)
1032 bp = linebuf + hppos - 1;
1033 /* special case: if about to wrap in the middle of maximum
1034 dungeon depth reached, wrap in front of it instead */
1035 if (bp > linebuf + 5 && !strncmp(bp - 5, " [max", 5))
1038 Strcpy(linebuf3, bp);
1040 Strcpy(linebuf3, bp + 1);
1043 while (bp < linebuf + (COLNO - 1))
1046 topten_print_bold(linebuf);
1048 topten_print(linebuf);
1049 Sprintf(linebuf, "%15s %s", "", linebuf3);
1050 lngr = strlen(linebuf);
1053 /* beginning of hp column not including padding */
1054 hppos = COLNO - 7 - (int) strlen(hpbuf);
1057 if (bp <= linebuf + hppos) {
1058 /* pad any necessary blanks to the hit point entry */
1059 while (bp < linebuf + hppos)
1062 Sprintf(eos(bp), " %s[%d]",
1063 (t1->maxhp < 10) ? " " : (t1->maxhp < 100) ? " " : "",
1071 while (bp < linebuf + so)
1074 topten_print_bold(linebuf);
1076 topten_print(linebuf);
1080 score_wanted(current_ver, rank, t1, playerct, players, uid)
1081 boolean current_ver;
1083 struct toptenentry *t1;
1085 const char **players;
1091 && (t1->ver_major != VERSION_MAJOR || t1->ver_minor != VERSION_MINOR
1092 || t1->patchlevel != PATCHLEVEL))
1095 if (sysopt.pers_is_uid && !playerct && t1->uid == uid)
1098 for (i = 0; i < playerct; i++) {
1099 if (players[i][0] == '-' && index("pr", players[i][1])
1100 && players[i][2] == 0 && i + 1 < playerct) {
1101 const char *arg = players[i + 1];
1102 if ((players[i][1] == 'p'
1103 && str2role(arg) == str2role(t1->plrole))
1104 || (players[i][1] == 'r'
1105 && str2race(arg) == str2race(t1->plrace)))
1108 } else if (strcmp(players[i], "all") == 0
1109 || strncmp(t1->name, players[i], NAMSZ) == 0
1110 || (players[i][0] == '-' && players[i][1] == t1->plrole[0]
1111 && players[i][2] == 0)
1112 || (digit(players[i][0]) && rank <= atoi(players[i])))
1119 * print selected parts of score list.
1120 * argc >= 2, with argv[0] untrustworthy (directory names, et al.),
1121 * and argv[1] starting with "-s".
1128 const char **players;
1130 boolean current_ver = TRUE, init_done = FALSE;
1131 register struct toptenentry *t1;
1133 boolean match_found = FALSE;
1137 const char *player0;
1139 if (argc < 2 || strncmp(argv[1], "-s", 2)) {
1140 raw_printf("prscore: bad arguments (%d)", argc);
1144 rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
1146 raw_print("Cannot open record file!");
1152 extern winid amii_rawprwin;
1154 init_nhwindows(&argc, argv);
1155 amii_rawprwin = create_nhwindow(NHW_TEXT);
1159 /* If the score list isn't after a game, we never went through
1160 * initialization. */
1161 if (wiz1_level.dlevel == 0) {
1167 if (!argv[1][2]) { /* plain "-s" */
1173 if (argc > 1 && !strcmp(argv[1], "-v")) {
1174 current_ver = FALSE;
1180 if (sysopt.pers_is_uid) {
1183 players = (const char **) 0;
1188 player0 = "all"; /* single user system */
1190 player0 = "hackplayer";
1197 players = (const char **) ++argv;
1201 t1 = tt_head = newttentry();
1202 for (rank = 1;; rank++) {
1203 readentry(rfile, t1);
1204 if (t1->points == 0)
1207 && score_wanted(current_ver, rank, t1, playerct, players, uid))
1209 t1->tt_next = newttentry();
1213 (void) fclose(rfile);
1222 for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
1223 if (score_wanted(current_ver, rank, t1, playerct, players, uid))
1224 (void) outentry(rank, t1, FALSE);
1227 Sprintf(pbuf, "Cannot find any %sentries for ",
1228 current_ver ? "current " : "");
1230 Strcat(pbuf, "you.");
1233 Strcat(pbuf, "any of ");
1234 for (i = 0; i < playerct; i++) {
1235 /* stop printing players if there are too many to fit */
1236 if (strlen(pbuf) + strlen(players[i]) + 2 >= BUFSZ) {
1237 if (strlen(pbuf) < BUFSZ - 4)
1238 Strcat(pbuf, "...");
1240 Strcpy(pbuf + strlen(pbuf) - 4, "...");
1243 Strcat(pbuf, players[i]);
1244 if (i < playerct - 1) {
1245 if (players[i][0] == '-' && index("pr", players[i][1])
1246 && players[i][2] == 0)
1254 raw_printf("Usage: %s -s [-v] <playertypes> [maxrank] [playernames]",
1257 raw_printf("Player types are: [-p role] [-r race]");
1259 free_ttlist(tt_head);
1262 extern winid amii_rawprwin;
1264 display_nhwindow(amii_rawprwin, 1);
1265 destroy_nhwindow(amii_rawprwin);
1266 amii_rawprwin = WIN_ERR;
1278 /* Look for this role in the role table */
1279 for (i = 0; roles[i].name.m; i++)
1280 if (!strncmp(plch, roles[i].filecode, ROLESZ)) {
1281 if (fem && roles[i].femalenum != NON_PM)
1282 return roles[i].femalenum;
1283 else if (roles[i].malenum != NON_PM)
1284 return roles[i].malenum;
1288 /* this might be from a 3.2.x score for former Elf class */
1289 if (!strcmp(plch, "E"))
1292 impossible("What weird role is this? (%s)", plch);
1293 return PM_HUMAN_MUMMY;
1297 * Get a random player name and class from the high score list,
1298 * and attach them to an object (for statues or morgue corpses).
1306 register struct toptenentry *tt;
1308 struct toptenentry tt_buf;
1311 return (struct obj *) 0;
1313 rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
1315 impossible("Cannot open record file!");
1316 return (struct obj *) 0;
1320 rank = rnd(sysopt.tt_oname_maxrank);
1322 for (i = rank; i; i--) {
1323 readentry(rfile, tt);
1324 if (tt->points == 0)
1328 if (tt->points == 0) {
1334 otmp = (struct obj *) 0;
1336 set_corpsenm(otmp, classmon(tt->plrole, (tt->plgend[0] == 'F')));
1337 otmp = oname(otmp, tt->name);
1340 (void) fclose(rfile);
1344 #ifdef NO_SCAN_BRACK
1345 /* Lattice scanf isn't up to reading the scorefile. What */
1346 /* follows deals with that; I admit it's ugly. (KL) */
1347 /* Now generally available (KL) */
1352 while ((p = index(p, ' ')) != 0)
1360 while ((p = index(p, '|')) != 0)
1363 #endif /* NO_SCAN_BRACK */