1 /* SCCS Id: @(#)topten.c 3.4 2000/01/21 */
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))
36 #define PERSMAX 3 /* entries per name/uid per char. allowed */
37 #define POINTSMIN 1 /* must be > 0 */
38 #define ENTRYMAX 100 /* must be >= 10 */
40 #if !defined(MICRO) && !defined(MAC) && !defined(WIN32)
41 #define PERS_IS_UID /* delete for PERSMAX per name; now per uid */
44 struct toptenentry *tt_next;
45 #ifdef UPDATE_RECORD_IN_PLACE
49 int deathdnum, deathlev;
50 int maxlvl, hp, maxhp, deaths;
51 int ver_major, ver_minor, patchlevel;
52 long deathdate, birthdate;
54 char plrole[ROLESZ+1];
55 char plrace[ROLESZ+1];
56 char plgend[ROLESZ+1];
57 char plalign[ROLESZ+1];
62 STATIC_DCL void FDECL(topten_print, (const char *));
63 STATIC_DCL void FDECL(topten_print_bold, (const char *));
64 STATIC_DCL xchar FDECL(observable_depth, (d_level *));
65 STATIC_DCL void NDECL(outheader);
66 STATIC_DCL void FDECL(outentry, (int,struct toptenentry *,BOOLEAN_P));
67 STATIC_DCL void FDECL(readentry, (FILE *,struct toptenentry *));
68 STATIC_DCL void FDECL(writeentry, (FILE *,struct toptenentry *));
69 STATIC_DCL void FDECL(free_ttlist, (struct toptenentry *));
70 STATIC_DCL int FDECL(classmon, (char *,BOOLEAN_P));
71 STATIC_DCL int FDECL(score_wanted,
72 (BOOLEAN_P, int,struct toptenentry *,int,const char **,int));
74 STATIC_DCL void FDECL(nsb_mung_line,(char*));
75 STATIC_DCL void FDECL(nsb_unmung_line,(char*));
78 /* must fit with end.c; used in rip.c */
79 NEARDATA const char * const killed_by_prefix[] = {
80 "killed by ", "choked on ", "poisoned by ", "died of ", "drowned in ",
81 "burned by ", "dissolved in ", "crushed to death by ", "petrified by ",
82 "turned to slime by ", "killed by ", "", "", "", "", ""
85 static winid toptenwin = WIN_ERR;
91 if (toptenwin == WIN_ERR)
94 putstr(toptenwin, ATR_NONE, x);
101 if (toptenwin == WIN_ERR)
104 putstr(toptenwin, ATR_BOLD, x);
108 observable_depth(lev)
111 #if 0 /* if we ever randomize the order of the elemental planes, we
112 must use a constant external representation in the record file */
113 if (In_endgame(lev)) {
114 if (Is_astralevel(lev)) return -5;
115 else if (Is_waterlevel(lev)) return -4;
116 else if (Is_firelevel(lev)) return -3;
117 else if (Is_airlevel(lev)) return -2;
118 else if (Is_earthlevel(lev)) return -1;
119 else return 0; /* ? */
128 struct toptenentry *tt;
130 #ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
131 static const char fmt[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c";
132 static const char fmt32[] = "%c%c %s %s%*c";
133 static const char fmt33[] = "%s %s %s %s %s %s%*c";
135 static const char fmt[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
136 static const char fmt32[] = "%c%c %[^,],%[^\n]%*c";
137 static const char fmt33[] = "%s %s %s %s %[^,],%[^\n]%*c";
140 #ifdef UPDATE_RECORD_IN_PLACE
141 /* note: fscanf() below must read the record's terminating newline */
142 final_fpos = tt->fpos = ftell(rfile);
145 if(fscanf(rfile, fmt,
146 &tt->ver_major, &tt->ver_minor, &tt->patchlevel,
147 &tt->points, &tt->deathdnum, &tt->deathlev,
148 &tt->maxlvl, &tt->hp, &tt->maxhp, &tt->deaths,
149 &tt->deathdate, &tt->birthdate,
150 &tt->uid) != TTFIELDS)
154 /* Check for backwards compatibility */
155 if (tt->ver_major < 3 ||
156 (tt->ver_major == 3 && tt->ver_minor < 3)) {
159 if (fscanf(rfile, fmt32,
160 tt->plrole, tt->plgend,
161 tt->name, tt->death) != 4)
163 tt->plrole[1] = '\0';
164 if ((i = str2role(tt->plrole)) >= 0)
165 Strcpy(tt->plrole, roles[i].filecode);
166 Strcpy(tt->plrace, "?");
167 Strcpy(tt->plgend, (tt->plgend[0] == 'M') ? "Mal" : "Fem");
168 Strcpy(tt->plalign, "?");
169 } else if (fscanf(rfile, fmt33,
170 tt->plrole, tt->plrace, tt->plgend,
171 tt->plalign, tt->name, tt->death) != 6)
175 nsb_unmung_line(tt->name);
176 nsb_unmung_line(tt->death);
181 /* check old score entries for Y2K problem and fix whenever found */
182 if (tt->points > 0) {
183 if (tt->birthdate < 19000000L) tt->birthdate += 19000000L;
184 if (tt->deathdate < 19000000L) tt->deathdate += 19000000L;
191 struct toptenentry *tt;
194 nsb_mung_line(tt->name);
195 nsb_mung_line(tt->death);
196 /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
197 (void) fprintf(rfile,"%d %d %d %ld %d %d %d %d %d %d %ld %ld %d ",
199 (void) fprintf(rfile,"%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ",
201 tt->ver_major, tt->ver_minor, tt->patchlevel,
202 tt->points, tt->deathdnum, tt->deathlev,
203 tt->maxlvl, tt->hp, tt->maxhp, tt->deaths,
204 tt->deathdate, tt->birthdate, tt->uid);
205 if (tt->ver_major < 3 ||
206 (tt->ver_major == 3 && tt->ver_minor < 3))
208 (void) fprintf(rfile,"%c%c %s %s\n",
210 (void) fprintf(rfile,"%c%c %s,%s\n",
212 tt->plrole[0], tt->plgend[0],
213 onlyspace(tt->name) ? "_" : tt->name, tt->death);
216 (void) fprintf(rfile,"%s %s %s %s %s %s\n",
218 (void) fprintf(rfile,"%s %s %s %s %s,%s\n",
220 tt->plrole, tt->plrace, tt->plgend, tt->plalign,
221 onlyspace(tt->name) ? "_" : tt->name, tt->death);
224 nsb_unmung_line(tt->name);
225 nsb_unmung_line(tt->death);
231 struct toptenentry *tt;
233 struct toptenentry *ttnext;
235 while (tt->points > 0) {
236 ttnext = tt->tt_next;
248 int rank, rank0 = -1, rank1 = 0;
249 int occ_cnt = PERSMAX;
250 register struct toptenentry *t0, *tprev;
251 struct toptenentry *t1;
253 register int flg = 0;
259 /* Under DICE 3.0, this crashes the system consistently, apparently due to
260 * corruption of *rfile somewhere. Until I figure this out, just cut out
261 * topten support entirely - at least then the game exits cleanly. --AC
267 /* If we are in the midst of a panic, cut out topten entirely.
268 * topten uses alloc() several times, which will lead to
269 * problems if the panic was the result of an alloc() failure.
271 if (program_state.panicking)
274 if (flags.toptenwin) {
275 toptenwin = create_nhwindow(NHW_TEXT);
278 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
279 #define HUP if (!program_state.done_hup)
285 restore_colors(); /* make sure the screen is black on white */
287 /* create a new 'topten' entry */
290 /* deepest_lev_reached() is in terms of depth(), and reporting the
291 * deepest level reached in the dungeon death occurred in doesn't
292 * seem right, so we have to report the death level in depth() terms
293 * as well (which also seems reasonable since that's all the player
294 * sees on the screen anyway)
296 t0->ver_major = VERSION_MAJOR;
297 t0->ver_minor = VERSION_MINOR;
298 t0->patchlevel = PATCHLEVEL;
299 t0->points = u.urexp;
300 t0->deathdnum = u.uz.dnum;
301 t0->deathlev = observable_depth(&u.uz);
302 t0->maxlvl = deepest_lev_reached(TRUE);
304 t0->maxhp = u.uhpmax;
305 t0->deaths = u.umortality;
307 (void) strncpy(t0->plrole, urole.filecode, ROLESZ);
308 t0->plrole[ROLESZ] = '\0';
309 (void) strncpy(t0->plrace, urace.filecode, ROLESZ);
310 t0->plrace[ROLESZ] = '\0';
311 (void) strncpy(t0->plgend, genders[flags.female].filecode, ROLESZ);
312 t0->plgend[ROLESZ] = '\0';
313 (void) strncpy(t0->plalign, aligns[1-u.ualign.type].filecode, ROLESZ);
314 t0->plalign[ROLESZ] = '\0';
315 (void) strncpy(t0->name, plname, NAMSZ);
316 t0->name[NAMSZ] = '\0';
318 switch (killer_format) {
319 default: impossible("bad killer format?");
321 Strcat(t0->death, killed_by_prefix[how]);
322 (void) strncat(t0->death, an(killer),
323 DTHSZ-strlen(t0->death));
326 Strcat(t0->death, killed_by_prefix[how]);
327 (void) strncat(t0->death, killer,
328 DTHSZ-strlen(t0->death));
330 case NO_KILLER_PREFIX:
331 (void) strncat(t0->death, killer, DTHSZ);
334 t0->birthdate = yyyymmdd(u.ubirthday);
335 t0->deathdate = yyyymmdd((time_t)0L);
337 #ifdef UPDATE_RECORD_IN_PLACE
341 #ifdef LOGFILE /* used for debugging (who dies of what, where) */
342 if (lock_file(LOGFILE, SCOREPREFIX, 10)) {
343 if(!(lfile = fopen_datafile(LOGFILE, "a", SCOREPREFIX))) {
344 HUP raw_print("Cannot open log file!");
346 writeentry(lfile, t0);
347 (void) fclose(lfile);
349 unlock_file(LOGFILE);
353 if (wizard || discover) {
354 if (how != PANICKED) HUP {
358 "Since you were in %s mode, the score list will not be checked.",
359 wizard ? "wizard" : "discover");
365 if (!lock_file(RECORD, SCOREPREFIX, 60))
368 #ifdef UPDATE_RECORD_IN_PLACE
369 rfile = fopen_datafile(RECORD, "r+", SCOREPREFIX);
371 rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
375 HUP raw_print("Cannot open record file!");
380 HUP topten_print("");
382 /* assure minimum number of points */
383 if(t0->points < POINTSMIN) t0->points = 0;
385 t1 = tt_head = newttentry();
387 /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
389 readentry(rfile, t1);
390 if (t1->points < POINTSMIN) t1->points = 0;
391 if(rank0 < 0 && t1->points < t0->points) {
398 #ifdef UPDATE_RECORD_IN_PLACE
399 t0->fpos = t1->fpos; /* insert here */
403 flg++; /* ask for a rewrite */
406 if(t1->points == 0) break;
409 t1->uid == t0->uid &&
411 strncmp(t1->name, t0->name, NAMSZ) == 0 &&
413 !strncmp(t1->plrole, t0->plrole, ROLESZ) &&
421 "You didn't beat your previous score of %ld points.",
432 if(rank <= ENTRYMAX) {
433 t1->tt_next = newttentry();
437 if(rank > ENTRYMAX) {
442 if(flg) { /* rewrite record file */
443 #ifdef UPDATE_RECORD_IN_PLACE
444 (void) fseek(rfile, (t0->fpos >= 0 ?
445 t0->fpos : final_fpos), SEEK_SET);
447 (void) fclose(rfile);
448 if(!(rfile = fopen_datafile(RECORD, "w", SCOREPREFIX))){
449 HUP raw_print("Cannot write record file");
451 free_ttlist(tt_head);
454 #endif /* UPDATE_RECORD_IN_PLACE */
455 if(!done_stopprint) if(rank0 > 0){
457 topten_print("You made the top ten list!");
461 "You reached the %d%s place on the top %d list.",
462 rank0, ordin(rank0), ENTRYMAX);
468 if(rank0 == 0) rank0 = rank1;
469 if(rank0 <= 0) rank0 = rank;
470 if(!done_stopprint) outheader();
472 for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
474 #ifdef UPDATE_RECORD_IN_PLACE
477 ) writeentry(rfile, t1);
478 if (done_stopprint) continue;
479 if (rank > flags.end_top &&
480 (rank < rank0 - flags.end_around ||
481 rank > rank0 + flags.end_around) &&
486 strncmp(t1->name, t0->name, NAMSZ)
489 if (rank == rank0 - flags.end_around &&
490 rank0 > flags.end_top + flags.end_around + 1 &&
494 outentry(rank, t1, FALSE);
496 outentry(rank, t1, TRUE);
498 outentry(rank, t1, TRUE);
499 outentry(0, t0, TRUE);
502 if(rank0 >= rank) if(!done_stopprint)
503 outentry(0, t0, TRUE);
504 #ifdef UPDATE_RECORD_IN_PLACE
506 # ifdef TRUNCATE_FILE
507 /* if a reasonable way to truncate a file exists, use it */
508 truncate_file(rfile);
510 /* use sentinel record rather than relying on truncation */
511 t1->points = 0L; /* terminates file when read back in */
512 t1->ver_major = t1->ver_minor = t1->patchlevel = 0;
513 t1->uid = t1->deathdnum = t1->deathlev = 0;
514 t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0;
515 t1->plrole[0] = t1->plrace[0] = t1->plgend[0] = t1->plalign[0] = '-';
516 t1->plrole[1] = t1->plrace[1] = t1->plgend[1] = t1->plalign[1] = 0;
517 t1->birthdate = t1->deathdate = yyyymmdd((time_t)0L);
518 Strcpy(t1->name, "@");
519 Strcpy(t1->death, "<eod>\n");
520 writeentry(rfile, t1);
521 (void) fflush(rfile);
522 # endif /* TRUNCATE_FILE */
524 #endif /* UPDATE_RECORD_IN_PLACE */
525 (void) fclose(rfile);
527 free_ttlist(tt_head);
530 if (flags.toptenwin && !done_stopprint) display_nhwindow(toptenwin, 1);
532 if (!t0_used) dealloc_ttentry(t0);
533 if (flags.toptenwin) {
534 destroy_nhwindow(toptenwin);
545 Strcpy(linebuf, " No Points Name");
547 while(bp < linebuf + COLNO - 9) *bp++ = ' ';
548 Strcpy(bp, "Hp [max]");
549 topten_print(linebuf);
552 /* so>0: standout line; so=0: ordinary line */
554 outentry(rank, t1, so)
555 struct toptenentry *t1;
559 boolean second_line = TRUE;
561 char *bp, hpbuf[24], linebuf3[BUFSZ];
566 if (rank) Sprintf(eos(linebuf), "%3d", rank);
567 else Strcat(linebuf, " ");
569 Sprintf(eos(linebuf), " %10ld %.10s", t1->points, t1->name);
570 Sprintf(eos(linebuf), "-%s", t1->plrole);
571 if (t1->plrace[0] != '?')
572 Sprintf(eos(linebuf), "-%s", t1->plrace);
573 /* Printing of gender and alignment is intentional. It has been
574 * part of the NetHack Geek Code, and illustrates a proper way to
575 * specify a character from the command line.
577 Sprintf(eos(linebuf), "-%s", t1->plgend);
578 if (t1->plalign[0] != '?')
579 Sprintf(eos(linebuf), "-%s ", t1->plalign);
581 Strcat(linebuf, " ");
582 if (!strncmp("escaped", t1->death, 7)) {
583 Sprintf(eos(linebuf), "escaped the dungeon %s[max level %d]",
584 !strncmp(" (", t1->death + 7, 2) ? t1->death + 7 + 2 : "",
586 /* fixup for closing paren in "escaped... with...Amulet)[max..." */
587 if ((bp = index(linebuf, ')')) != 0)
588 *bp = (t1->deathdnum == astral_level.dnum) ? '\0' : ' ';
590 } else if (!strncmp("ascended", t1->death, 8)) {
591 Sprintf(eos(linebuf), "ascended to demigod%s-hood",
592 (t1->plgend[0] == 'F') ? "dess" : "");
595 if (!strncmp(t1->death, "quit", 4)) {
596 Strcat(linebuf, "quit");
598 } else if (!strncmp(t1->death, "died of st", 10)) {
599 Strcat(linebuf, "starved to death");
601 } else if (!strncmp(t1->death, "choked", 6)) {
602 Sprintf(eos(linebuf), "choked on h%s food",
603 (t1->plgend[0] == 'F') ? "er" : "is");
604 } else if (!strncmp(t1->death, "poisoned", 8)) {
605 Strcat(linebuf, "was poisoned");
606 } else if (!strncmp(t1->death, "crushed", 7)) {
607 Strcat(linebuf, "was crushed to death");
608 } else if (!strncmp(t1->death, "petrified by ", 13)) {
609 Strcat(linebuf, "turned to stone");
610 } else Strcat(linebuf, "died");
612 if (t1->deathdnum == astral_level.dnum) {
613 const char *arg, *fmt = " on the Plane of %s";
615 switch (t1->deathlev) {
617 fmt = " on the %s Plane";
618 arg = "Astral"; break;
620 arg = "Water"; break;
626 arg = "Earth"; break;
630 Sprintf(eos(linebuf), fmt, arg);
632 Sprintf(eos(linebuf), " in %s", dungeons[t1->deathdnum].dname);
633 if (t1->deathdnum != knox_level.dnum)
634 Sprintf(eos(linebuf), " on level %d", t1->deathlev);
635 if (t1->deathlev != t1->maxlvl)
636 Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
639 /* kludge for "quit while already on Charon's boat" */
640 if (!strncmp(t1->death, "quit ", 5))
641 Strcat(linebuf, t1->death + 4);
643 Strcat(linebuf, ".");
645 /* Quit, starved, ascended, and escaped contain no second line */
647 Sprintf(eos(linebuf), " %c%s.", highc(*(t1->death)), t1->death+1);
649 lngr = (int)strlen(linebuf);
650 if (t1->hp <= 0) hpbuf[0] = '-', hpbuf[1] = '\0';
651 else Sprintf(hpbuf, "%d", t1->hp);
652 /* beginning of hp column after padding (not actually padded yet) */
653 hppos = COLNO - (sizeof(" Hp [max]")-1); /* sizeof(str) includes \0 */
654 while (lngr >= hppos) {
655 for(bp = eos(linebuf);
656 !(*bp == ' ' && (bp-linebuf < hppos));
659 /* special case: if about to wrap in the middle of maximum
660 dungeon depth reached, wrap in front of it instead */
661 if (bp > linebuf + 5 && !strncmp(bp - 5, " [max", 5)) bp -= 5;
662 Strcpy(linebuf3, bp+1);
665 while (bp < linebuf + (COLNO-1)) *bp++ = ' ';
667 topten_print_bold(linebuf);
669 topten_print(linebuf);
670 Sprintf(linebuf, "%15s %s", "", linebuf3);
671 lngr = strlen(linebuf);
673 /* beginning of hp column not including padding */
674 hppos = COLNO - 7 - (int)strlen(hpbuf);
677 if (bp <= linebuf + hppos) {
678 /* pad any necessary blanks to the hit point entry */
679 while (bp < linebuf + hppos) *bp++ = ' ';
681 Sprintf(eos(bp), " %s[%d]",
682 (t1->maxhp < 10) ? " " : (t1->maxhp < 100) ? " " : "",
688 if (so >= COLNO) so = COLNO-1;
689 while (bp < linebuf + so) *bp++ = ' ';
691 topten_print_bold(linebuf);
693 topten_print(linebuf);
697 score_wanted(current_ver, rank, t1, playerct, players, uid)
700 struct toptenentry *t1;
702 const char **players;
707 if (current_ver && (t1->ver_major != VERSION_MAJOR ||
708 t1->ver_minor != VERSION_MINOR ||
709 t1->patchlevel != PATCHLEVEL))
713 if (!playerct && t1->uid == uid)
717 for (i = 0; i < playerct; i++) {
718 if (players[i][0] == '-' && index("pr", players[i][1]) &&
719 players[i][2] == 0 && i + 1 < playerct) {
720 char *arg = (char *)players[i + 1];
721 if ((players[i][1] == 'p' &&
722 str2role(arg) == str2role(t1->plrole)) ||
723 (players[i][1] == 'r' &&
724 str2race(arg) == str2race(t1->plrace)))
727 } else if (strcmp(players[i], "all") == 0 ||
728 strncmp(t1->name, players[i], NAMSZ) == 0 ||
729 (players[i][0] == '-' &&
730 players[i][1] == t1->plrole[0] &&
731 players[i][2] == 0) ||
732 (digit(players[i][0]) && rank <= atoi(players[i])))
739 * print selected parts of score list.
740 * argc >= 2, with argv[0] untrustworthy (directory names, et al.),
741 * and argv[1] starting with "-s".
748 const char **players;
750 boolean current_ver = TRUE, init_done = FALSE;
751 register struct toptenentry *t1;
753 boolean match_found = FALSE;
761 if (argc < 2 || strncmp(argv[1], "-s", 2)) {
762 raw_printf("prscore: bad arguments (%d)", argc);
766 rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
768 raw_print("Cannot open record file!");
774 extern winid amii_rawprwin;
775 init_nhwindows(&argc, argv);
776 amii_rawprwin = create_nhwindow(NHW_TEXT);
780 /* If the score list isn't after a game, we never went through
782 if (wiz1_level.dlevel == 0) {
788 if (!argv[1][2]){ /* plain "-s" */
793 if (argc > 1 && !strcmp(argv[1], "-v")) {
803 players = (const char **)0;
808 player0 = "all"; /* single user system */
810 player0 = "hackplayer";
817 players = (const char **)++argv;
821 t1 = tt_head = newttentry();
822 for (rank = 1; ; rank++) {
823 readentry(rfile, t1);
824 if (t1->points == 0) break;
826 score_wanted(current_ver, rank, t1, playerct, players, uid))
828 t1->tt_next = newttentry();
832 (void) fclose(rfile);
841 for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
842 if (score_wanted(current_ver, rank, t1, playerct, players, uid))
843 (void) outentry(rank, t1, 0);
846 Sprintf(pbuf, "Cannot find any %sentries for ",
847 current_ver ? "current " : "");
848 if (playerct < 1) Strcat(pbuf, "you.");
850 if (playerct > 1) Strcat(pbuf, "any of ");
851 for (i = 0; i < playerct; i++) {
852 /* stop printing players if there are too many to fit */
853 if (strlen(pbuf) + strlen(players[i]) + 2 >= BUFSZ) {
854 if (strlen(pbuf) < BUFSZ-4) Strcat(pbuf, "...");
855 else Strcpy(pbuf+strlen(pbuf)-4, "...");
858 Strcat(pbuf, players[i]);
859 if (i < playerct-1) {
860 if (players[i][0] == '-' &&
861 index("pr", players[i][1]) && players[i][2] == 0)
863 else Strcat(pbuf, ":");
868 raw_printf("Usage: %s -s [-v] <playertypes> [maxrank] [playernames]",
871 raw_printf("Player types are: [-p role] [-r race]");
873 free_ttlist(tt_head);
876 extern winid amii_rawprwin;
877 display_nhwindow(amii_rawprwin, 1);
878 destroy_nhwindow(amii_rawprwin);
879 amii_rawprwin = WIN_ERR;
891 /* Look for this role in the role table */
892 for (i = 0; roles[i].name.m; i++)
893 if (!strncmp(plch, roles[i].filecode, ROLESZ)) {
894 if (fem && roles[i].femalenum != NON_PM)
895 return roles[i].femalenum;
896 else if (roles[i].malenum != NON_PM)
897 return roles[i].malenum;
901 /* this might be from a 3.2.x score for former Elf class */
902 if (!strcmp(plch, "E")) return PM_RANGER;
904 impossible("What weird role is this? (%s)", plch);
905 return (PM_HUMAN_MUMMY);
909 * Get a random player name and class from the high score list,
910 * and attach them to an object (for statues or morgue corpses).
918 register struct toptenentry *tt;
920 struct toptenentry tt_buf;
922 if (!otmp) return((struct obj *) 0);
924 rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
926 impossible("Cannot open record file!");
927 return (struct obj *)0;
933 for(i = rank; i; i--) {
934 readentry(rfile, tt);
935 if(tt->points == 0) break;
938 if(tt->points == 0) {
944 otmp = (struct obj *) 0;
946 /* reset timer in case corpse started out as lizard or troll */
947 if (otmp->otyp == CORPSE) obj_stop_timers(otmp);
948 otmp->corpsenm = classmon(tt->plrole, (tt->plgend[0] == 'F'));
949 otmp->owt = weight(otmp);
950 otmp = oname(otmp, tt->name);
951 if (otmp->otyp == CORPSE) start_corpse_timeout(otmp);
954 (void) fclose(rfile);
959 /* Lattice scanf isn't up to reading the scorefile. What */
960 /* follows deals with that; I admit it's ugly. (KL) */
961 /* Now generally available (KL) */
966 while ((p = index(p, ' ')) != 0) *p = '|';
973 while ((p = index(p, '|')) != 0) *p = ' ';
975 #endif /* NO_SCAN_BRACK */