Source:NetHack 3.1.0/topten.c

From NetHackWiki
(Redirected from NetHack 3.1.0/topten.c)
Jump to navigation Jump to search

Below is the full text to topten.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.0/topten.c#line123]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)topten.c	3.1	92/11/20	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #include "hack.h"
6.    
7.    #ifdef VMS
8.     /* We don't want to rewrite the whole file, because that entails	 */
9.     /* creating a new version which requires that the old one be deletable. */
10.   # define UPDATE_RECORD_IN_PLACE
11.   #endif
12.   
13.   /*
14.    * Updating in place can leave junk at the end of the file in some
15.    * circumstances (if it shrinks and the O.S. doesn't have a straightforward
16.    * way to truncate it).  The trailing junk is harmless and the code
17.    * which reads the scores will ignore it.
18.    */
19.   #ifdef UPDATE_RECORD_IN_PLACE
20.   # ifndef SEEK_SET
21.   #  define SEEK_SET 0
22.   # endif
23.   static long final_fpos;
24.   #endif
25.   
26.   #ifdef NO_SCAN_BRACK
27.   static void FDECL(nsb_mung_line,(char*));
28.   static void FDECL(nsb_unmung_line,(char*));
29.   #endif
30.   
31.   #define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
32.   #define dealloc_ttentry(ttent) free((genericptr_t) (ttent))
33.   #define	NAMSZ	10
34.   #define	DTHSZ	60
35.   #define	PERSMAX	 3		/* entries per name/uid per char. allowed */
36.   #define	POINTSMIN	1	/* must be > 0 */
37.   #define	ENTRYMAX	100	/* must be >= 10 */
38.   
39.   #ifndef MICRO
40.   #define	PERS_IS_UID		/* delete for PERSMAX per name; now per uid */
41.   #endif
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;
50.   	int uid;
51.   	char plchar;
52.   	char sex;
53.   	char name[NAMSZ+1];
54.   	char death[DTHSZ+1];
55.   	char date[7];		/* yymmdd */
56.   } *tt_head;
57.   
58.   static void NDECL(outheader);
59.   static int FDECL(outentry, (int,struct toptenentry *,int));
60.   static void FDECL(readentry, (FILE *,struct toptenentry *));
61.   static void FDECL(writeentry, (FILE *,struct toptenentry *));
62.   static int FDECL(classmon, (CHAR_P,BOOLEAN_P));
63.   
64.   /* must fit with end.c */
65.   const char NEARDATA *killed_by_prefix[] = {
66.   	"killed by ", "choked on ", "poisoned by ", "", "drowned in ",
67.   	"", "crushed to death by ", "petrified by ", "",
68.   	"", "",
69.   	"", "", "" };
70.   
71.   static void
72.   readentry(rfile,tt)
73.   FILE *rfile;
74.   struct toptenentry *tt;
75.   {
76.   #ifdef UPDATE_RECORD_IN_PLACE
77.   	/* note: fscanf() below must read the record's terminating newline */
78.   	final_fpos = tt->fpos = ftell(rfile);
79.   #endif
80.   #ifdef NO_SCAN_BRACK
81.   	if(fscanf(rfile,"%6s %d %d %d %d %d %d %ld%*c%c%c %s %s%*c",
82.   #  define TTFIELDS 13
83.   #else
84.   	if(fscanf(rfile, "%6s %d %d %d %d %d %d %ld %c%c %[^,],%[^\n]%*c",
85.   #  define TTFIELDS 12
86.   #endif
87.   			tt->date, &tt->uid,
88.   			&tt->deathdnum, &tt->deathlev,
89.   			&tt->maxlvl, &tt->hp, &tt->maxhp, &tt->points,
90.   			&tt->plchar, &tt->sex,
91.   #ifdef LATTICE	/* return value is broken also, sigh */
92.   			tt->name, tt->death) < 1)
93.   #else
94.   			tt->name, tt->death) != TTFIELDS)
95.   #endif
96.   #undef TTFIELDS
97.   		tt->points = 0;
98.   	else {
99.   #ifdef NO_SCAN_BRACK
100.  		if(tt->points > 0) {
101.  			nsb_unmung_line(tt->name);
102.  			nsb_unmung_line(tt->death);
103.  		}
104.  #endif
105.  	}
106.  }
107.  
108.  static void
109.  writeentry(rfile,tt)
110.  FILE *rfile;
111.  struct toptenentry *tt;
112.  {
113.  #ifdef NO_SCAN_BRACK
114.  	nsb_mung_line(tt->name);
115.  	nsb_mung_line(tt->death);
116.  	(void) fprintf(rfile,"%6s %d %d %d %d %d %d %ld %c%c %s %s\n",
117.  #else
118.  	(void) fprintf(rfile,"%6s %d %d %d %d %d %d %ld %c%c %s,%s\n",
119.  #endif
120.  		tt->date, tt->uid,
121.  		tt->deathdnum, tt->deathlev,
122.  		tt->maxlvl, tt->hp, tt->maxhp, tt->points,
123.  		tt->plchar, tt->sex,
124.  		onlyspace(tt->name) ? "_" : tt->name, tt->death);
125.  #ifdef NO_SCAN_BRACK
126.  	nsb_unmung_line(tt->name);
127.  	nsb_unmung_line(tt->death);
128.  #endif
129.  }
130.  
131.  void
132.  topten(how)
133.  int how;
134.  {
135.  	int uid = getuid();
136.  	int rank, rank0 = -1, rank1 = 0;
137.  	int occ_cnt = PERSMAX;
138.  	register struct toptenentry *t0, *tprev;
139.  	struct toptenentry *t1;
140.  	FILE *rfile;
141.  	register int flg = 0;
142.  #ifdef LOGFILE
143.  	FILE *lfile;
144.  #endif /* LOGFILE */
145.  
146.  #if defined(MICRO)
147.  #define HUP
148.  #else
149.  #define	HUP	if(!done_hup)
150.  #endif
151.  	/* create a new 'topten' entry */
152.  	t0 = newttentry();
153.  	/* deepest_lev_reached() is in terms of depth(), and reporting the
154.  	 * deepest level reached in the dungeon death occurred in doesn't
155.  	 * seem right, so we have to report the death level in depth() terms
156.  	 * as well (which also seems reasonable since that's all the player
157.  	 * sees on the screen anyway)
158.  	 */
159.  	t0->deathdnum = u.uz.dnum;
160.  	t0->deathlev = depth(&u.uz);
161.  	t0->maxlvl = deepest_lev_reached(TRUE);
162.  	t0->hp = u.uhp;
163.  	t0->maxhp = u.uhpmax;
164.  	t0->points = u.urexp;
165.  	t0->plchar = pl_character[0];
166.  	t0->sex = (flags.female ? 'F' : 'M');
167.  	t0->uid = uid;
168.  	(void) strncpy(t0->name, plname, NAMSZ);
169.  	t0->name[NAMSZ] = '\0';
170.  	t0->death[0] = '\0';
171.  	switch (killer_format) {
172.  		default: impossible("bad killer format?");
173.  		case KILLED_BY_AN:
174.  			Strcat(t0->death, killed_by_prefix[how]);
175.  			(void) strncat(t0->death, an(killer), DTHSZ);
176.  			break;
177.  		case KILLED_BY:
178.  			Strcat(t0->death, killed_by_prefix[how]);
179.  			(void) strncat(t0->death, killer, DTHSZ);
180.  			break;
181.  		case NO_KILLER_PREFIX:
182.  			(void) strncat(t0->death, killer, DTHSZ);
183.  			break;
184.  	}
185.  	Strcpy(t0->date, get_date());
186.  	t0->tt_next = 0;
187.  #ifdef UPDATE_RECORD_IN_PLACE
188.  	t0->fpos = -1L;
189.  #endif
190.  
191.  #ifdef LOGFILE		/* used for debugging (who dies of what, where) */
192.  	if (lock_file(LOGFILE, 10)) {
193.  	    if(!(lfile = fopen_datafile(LOGFILE,"a"))) {
194.  		HUP raw_print("Cannot open log file!");
195.  	    } else {
196.  		writeentry(lfile, t0);
197.  		(void) fclose(lfile);
198.  	    }
199.  	    unlock_file(LOGFILE);
200.  	}
201.  #endif /* LOGFILE */
202.  
203.  #if defined(WIZARD) || defined(EXPLORE_MODE)
204.  	if (wizard || discover) {
205.  	    raw_print("");
206.  	    raw_printf(
207.  	      "Since you were in %s mode, the score list will not be checked.",
208.  		    wizard ? "wizard" : "discover");
209.  	    return;
210.  	}
211.  #endif
212.  
213.  	if (!lock_file(RECORD, 60)) return;
214.  
215.  #ifdef UPDATE_RECORD_IN_PLACE
216.  	rfile = fopen_datafile(RECORD, "r+");
217.  #else
218.  	rfile = fopen_datafile(RECORD, "r");
219.  #endif
220.  
221.  	if (!rfile) {
222.  		HUP raw_print("Cannot open record file!");
223.  		unlock_file(RECORD);
224.  		return;
225.  	}
226.  
227.  	HUP raw_print("");
228.  
229.  	/* assure minimum number of points */
230.  	if(t0->points < POINTSMIN) t0->points = 0;
231.  
232.  	t1 = tt_head = newttentry();
233.  	tprev = 0;
234.  	/* rank0: -1 undefined, 0 not_on_list, n n_th on list */
235.  	for(rank = 1; ; ) {
236.  	    readentry(rfile, t1);
237.  	    if (t1->points < POINTSMIN) t1->points = 0;
238.  	    if(rank0 < 0 && t1->points < t0->points) {
239.  		rank0 = rank++;
240.  		if(tprev == 0)
241.  			tt_head = t0;
242.  		else
243.  			tprev->tt_next = t0;
244.  		t0->tt_next = t1;
245.  #ifdef UPDATE_RECORD_IN_PLACE
246.  		t0->fpos = t1->fpos;	/* insert here */
247.  #endif
248.  		occ_cnt--;
249.  		flg++;		/* ask for a rewrite */
250.  	    } else tprev = t1;
251.  
252.  	    if(t1->points == 0) break;
253.  	    if(
254.  #ifdef PERS_IS_UID
255.  		t1->uid == t0->uid &&
256.  #else
257.  		strncmp(t1->name, t0->name, NAMSZ) == 0 &&
258.  #endif
259.  		t1->plchar == t0->plchar && --occ_cnt <= 0) {
260.  		    if(rank0 < 0) {
261.  			rank0 = 0;
262.  			rank1 = rank;
263.  			HUP {
264.  			    raw_printf(
265.  			  "You didn't beat your previous score of %ld points.",
266.  				    t1->points);
267.  			    raw_print("");
268.  			}
269.  		    }
270.  		    if(occ_cnt < 0) {
271.  			flg++;
272.  			continue;
273.  		    }
274.  		}
275.  	    if(rank <= ENTRYMAX) {
276.  		t1 = t1->tt_next = newttentry();
277.  		rank++;
278.  	    }
279.  	    if(rank > ENTRYMAX) {
280.  		t1->points = 0;
281.  		break;
282.  	    }
283.  	}
284.  	if(flg) {	/* rewrite record file */
285.  #ifdef UPDATE_RECORD_IN_PLACE
286.  		(void) fseek(rfile, (t0->fpos >= 0 ?
287.  				     t0->fpos : final_fpos), SEEK_SET);
288.  #else
289.  		(void) fclose(rfile);
290.  		if(!(rfile = fopen_datafile(RECORD,"w"))){
291.  			HUP raw_print("Cannot write record file");
292.  			unlock_file(RECORD);
293.  			return;
294.  		}
295.  #endif	/* UPDATE_RECORD_IN_PLACE */
296.  		if(!done_stopprint) if(rank0 > 0){
297.  		    if(rank0 <= 10)
298.  			raw_print("You made the top ten list!");
299.  		    else {
300.  			raw_printf(
301.  			  "You reached the %d%s place on the top %d list.",
302.  				rank0, ordin(rank0), ENTRYMAX);
303.  		    }
304.  		    raw_print("");
305.  		}
306.  	}
307.  	if(rank0 == 0) rank0 = rank1;
308.  	if(rank0 <= 0) rank0 = rank;
309.  	if(!done_stopprint) outheader();
310.  	t1 = tt_head;
311.  	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
312.  	    if(flg
313.  #ifdef UPDATE_RECORD_IN_PLACE
314.  		    && rank >= rank0
315.  #endif
316.  		) writeentry(rfile, t1);
317.  	    if(done_stopprint) continue;
318.  	    if(rank > flags.end_top &&
319.  	      (rank < rank0-flags.end_around || rank > rank0+flags.end_around)
320.  	      && (!flags.end_own ||
321.  #ifdef PERS_IS_UID
322.  				  t1->uid != t0->uid
323.  #else
324.  				  strncmp(t1->name, t0->name, NAMSZ)
325.  #endif
326.  		)) continue;
327.  	    if(rank == rank0-flags.end_around &&
328.  	       rank0 > flags.end_top+flags.end_around+1 &&
329.  	       !flags.end_own)
330.  	  	raw_print("");
331.  	    if(rank != rank0)
332.  		(void) outentry(rank, t1, 0);
333.  	    else if(!rank1)
334.  		(void) outentry(rank, t1, 1);
335.  	    else {
336.  		int t0lth = outentry(0, t0, -1);
337.  		int t1lth = outentry(rank, t1, t0lth);
338.  		if(t1lth > t0lth) t0lth = t1lth;
339.  		(void) outentry(0, t0, t0lth);
340.  	    }
341.  	}
342.  	if(rank0 >= rank) if(!done_stopprint)
343.  		(void) outentry(0, t0, 1);
344.  #ifdef UPDATE_RECORD_IN_PLACE
345.  	if (flg) {
346.  # ifdef TRUNCATE_FILE
347.  		/* if a reasonable way to truncate a file exists, use it */
348.  		truncate_file(rfile);
349.  # else
350.  		/* use sentinel record rather than relying on truncation */
351.  		t0->points = 0L;	/* terminates file when read back in */
352.  		t0->uid = t0->deathdnum = t0->deathlev = 0;
353.  		t0->maxlvl = t0->hp = t0->maxhp = 0;
354.  		t0->plchar = t0->sex = '-';
355.  		Strcpy(t0->name, "@");
356.  		Strcpy(t0->death, "<eod>\n");
357.  		writeentry(rfile, t0);
358.  		(void) fflush(rfile);
359.  # endif	/* TRUNCATE_FILE */
360.  	}
361.  #endif	/* UPDATE_RECORD_IN_PLACE */
362.  	(void) fclose(rfile);
363.  	unlock_file(RECORD);
364.  }
365.  
366.  static void
367.  outheader() {
368.  	char linebuf[BUFSZ];
369.  	register char *bp;
370.  
371.  	Strcpy(linebuf, " No  Points     Name");
372.  	bp = eos(linebuf);
373.  	while(bp < linebuf + COLNO - 9) *bp++ = ' ';
374.  	Strcpy(bp, "Hp [max]");
375.  	raw_print(linebuf);
376.  }
377.  
378.  /* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */
379.  static int
380.  outentry(rank, t1, so)
381.  register struct toptenentry *t1;
382.  register int rank, so;
383.  {
384.  	register boolean second_line = TRUE;
385.  	char linebuf[BUFSZ], linebuf2[BUFSZ], linebuf3[BUFSZ], pbuf[BUFSZ];
386.  
387.  	linebuf[0] = linebuf2[0] = linebuf3[0] = 0;
388.  	if(rank) Sprintf(eos(linebuf), "%3d", rank);
389.  	else Strcat(linebuf, "   ");
390.  
391.  	Sprintf(eos(linebuf), " %10ld  %.10s", t1->points, t1->name);
392.  	Sprintf(eos(linebuf), "-%c ", t1->plchar);
393.  	if(!strncmp("escaped", t1->death, 7)) {
394.  	  second_line = FALSE;
395.  	  if(!strcmp(" (with the Amulet)", t1->death+7))
396.  	    Strcat(linebuf, "escaped the dungeon with the Amulet");
397.  	  else
398.  	    Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",
399.  	      t1->maxlvl);
400.  	} else if(!strncmp("ascended", t1->death, 8)) {
401.  	   Strcat(linebuf, "ascended to demigod");
402.  	   if (t1->sex == 'F') Strcat(linebuf, "dess");
403.  	   Strcat(linebuf, "-hood");
404.  	   second_line = FALSE;
405.  	} else {
406.  	  if(!strncmp(t1->death,"quit",4)) {
407.  		Strcat(linebuf, "quit");
408.  		second_line = FALSE;
409.  	  } else if(!strncmp(t1->death,"starv",5)) {
410.  		Strcat(linebuf, "starved to death");
411.  		second_line = FALSE;
412.  	  } else if(!strncmp(t1->death,"choked",6)) {
413.  		Sprintf(eos(linebuf), "choked on h%s food",
414.  			(t1->sex == 'F') ? "er" : "is");
415.  	  } else if(!strncmp(t1->death,"poisoned",8)) {
416.  		Strcat(linebuf, "was poisoned");
417.  	  } else if(!strncmp(t1->death,"crushed",7)) {
418.  		Strcat(linebuf, "was crushed to death");
419.  	  } else if(!strncmp(t1->death, "petrified by ",13)) {
420.  		Strcat(linebuf, "turned to stone");
421.  	  } else Strcat(linebuf, "died");
422.  
423.  	  if (t1->deathdnum == astral_level.dnum)
424.  		Strcpy(linebuf3, " in the endgame");
425.  	  else
426.  		Sprintf(linebuf3, " in %s on level %d",
427.  		    dungeons[t1->deathdnum].dname, t1->deathlev);
428.  	  if(t1->deathlev != t1->maxlvl)
429.  		Sprintf(eos(linebuf3), " [max %d]", t1->maxlvl);
430.  	  /* kludge for "quit while already on Charon's boat" */
431.  	  if(!strncmp(t1->death, "quit ", 5))
432.  		Strcat(linebuf3, t1->death + 4);
433.  	}
434.  	Strcat(linebuf3, ".");
435.  
436.  	if(t1->maxhp) {
437.  	  register char *bp;
438.  	  char hpbuf[10];
439.  	  int hppos;
440.  	  int lngr = strlen(linebuf) + strlen(linebuf3);
441.  	  if (t1->hp <= 0) hpbuf[0] = '-', hpbuf[1] = '\0';
442.  	  else Sprintf(hpbuf, "%d", t1->hp);
443.  	  hppos = COLNO - 7 - (int)strlen(hpbuf);
444.  	  if (lngr >= hppos) {
445.  	      if(so > 0) {
446.  		  bp = eos(linebuf);
447.  		  while(bp < linebuf + (COLNO-1)) *bp++ = ' ';
448.  		  *bp = 0;
449.  		  raw_print_bold(linebuf);
450.  	      } else if(so == 0)
451.  		  raw_print(linebuf);
452.  	      Strcpy(linebuf, "               ");
453.  	  }
454.  	  Strcat(linebuf, linebuf3);
455.  	  bp = eos(linebuf);
456.  
457.  	  if(bp <= linebuf + hppos) {
458.  	    /* pad any necessary blanks to the hit point entry */
459.  	    while(bp < linebuf + hppos) *bp++ = ' ';
460.  	    Strcpy(bp, hpbuf);
461.  	    if(t1->maxhp < 10)
462.  		 Sprintf(eos(bp), "   [%d]", t1->maxhp);
463.  	    else if(t1->maxhp < 100)
464.  		 Sprintf(eos(bp), "  [%d]", t1->maxhp);
465.  	    else Sprintf(eos(bp), " [%d]", t1->maxhp);
466.  	  }
467.  	}
468.  
469.  /*	Line 2 now contains the killer name */
470.  
471.  	/* Quit, starved, ascended, and escaped contain no second line */
472.  	if (second_line) {
473.  		Strcpy(linebuf2, t1->death);
474.  		*linebuf2 = highc(*linebuf2);
475.  		Strcat(linebuf2, ".");
476.  	}
477.  
478.  	if(so == 0) {
479.  	    raw_print(linebuf);
480.  	    if (second_line)
481.  		raw_printf("                %s", linebuf2);
482.  	} else if(so > 0) {
483.  	  register char *bp = eos(linebuf);
484.  	  if(so >= COLNO) so = COLNO-1;
485.  	  while(bp < linebuf + so) *bp++ = ' ';
486.  	  *bp = 0;
487.  	  raw_print_bold(linebuf);
488.  	  if(second_line) {
489.  	      Sprintf(pbuf, "                %s", linebuf2);
490.  	      raw_print_bold(pbuf);
491.  	  }
492.  	}
493.  	return((int)strlen(linebuf)+(int)strlen(linebuf2));
494.  }
495.  
496.  /*
497.   * Called with args from main if argc >= 0. In this case, list scores as
498.   * requested. Otherwise, find scores for the current player (and list them
499.   * if argc == -1).
500.   */
501.  void
502.  prscore(argc,argv)
503.  int argc;
504.  char **argv;
505.  {
506.  	const char **players;
507.  	int playerct;
508.  	int rank;
509.  	register struct toptenentry *t1, *t2;
510.  	FILE *rfile;
511.  	register int flg = 0, i;
512.  	char pbuf[BUFSZ];
513.  #ifdef nonsense
514.  	long total_score = 0L;
515.  	char totchars[10];
516.  	int totcharct = 0;
517.  #endif
518.  	int outflg = (argc >= -1);
519.  #ifdef PERS_IS_UID
520.  	int uid = -1;
521.  #else
522.  	const char *player0;
523.  #endif
524.  	rfile = fopen_datafile(RECORD, "r");
525.  	if (!rfile) {
526.  		raw_print("Cannot open record file!");
527.  		return;
528.  	}
529.  
530.  	/* If the score list isn't after a game, we never went through */
531.  	/* init_dungeons() */
532.  	if (wiz1_level.dlevel == 0) init_dungeons();
533.  
534.  	if(argc > 1 && !strncmp(argv[1], "-s", 2)){
535.  		if(!argv[1][2]){
536.  			argc--;
537.  			argv++;
538.  		} else if(!argv[1][3] && index(pl_classes, argv[1][2])) {
539.  			argv[1]++;
540.  			argv[1][0] = '-';
541.  		} else	argv[1] += 2;
542.  	}
543.  	if(argc <= 1){
544.  #ifdef PERS_IS_UID
545.  		uid = getuid();
546.  		playerct = 0;
547.  #  if defined(LINT) || defined(GCC_WARN)
548.  		players = 0;
549.  #  endif
550.  #else
551.  		player0 = plname;
552.  		if(!*player0)
553.  			player0 = "hackplayer";
554.  		playerct = 1;
555.  		players = &player0;
556.  #endif
557.  	} else {
558.  		playerct = --argc;
559.  		players = (const char **)++argv;
560.  	}
561.  	if(outflg) raw_print("");
562.  
563.  	t1 = tt_head = newttentry();
564.  	for(rank = 1; ; rank++) {
565.  	    readentry(rfile, t1);
566.  	    if(t1->points == 0) break;
567.  #ifdef PERS_IS_UID
568.  	    if(!playerct && t1->uid == uid)
569.  		flg++;
570.  	    else
571.  #endif
572.  	    for(i = 0; i < playerct; i++){
573.  		if(strcmp(players[i], "all") == 0 ||
574.  		   strncmp(t1->name, players[i], NAMSZ) == 0 ||
575.  		  (players[i][0] == '-' &&
576.  		   players[i][1] == t1->plchar &&
577.  		   players[i][2] == 0) ||
578.  		  (digit(players[i][0]) && rank <= atoi(players[i])))
579.  			flg++;
580.  	    }
581.  	    t1 = t1->tt_next = newttentry();
582.  	}
583.  	(void) fclose(rfile);
584.  	if(!flg) {
585.  	    if(outflg) {
586.  		Strcpy(pbuf, "Cannot find any entries for ");
587.  		if(playerct < 1) Strcat(pbuf, "you.");
588.  		else {
589.  		  if(playerct > 1) Strcat(pbuf, "any of ");
590.  		  for(i=0; i<playerct; i++) {
591.  		      Strcat(pbuf, players[i]);
592.  		      if(i<playerct-1) Strcat(pbuf, ":");
593.  		  }
594.  		  raw_print(pbuf);
595.  		  raw_printf("Call is: %s -s [-role] [maxrank] [playernames]",
596.  			     hname);
597.  		}
598.  	    }
599.  	    return;
600.  	}
601.  
602.  	if(outflg) outheader();
603.  	t1 = tt_head;
604.  	for(rank = 1; t1->points != 0; rank++, t1 = t2) {
605.  		t2 = t1->tt_next;
606.  #ifdef PERS_IS_UID
607.  		if(!playerct && t1->uid == uid)
608.  			goto outwithit;
609.  		else
610.  #endif
611.  		for(i = 0; i < playerct; i++){
612.  			if(strcmp(players[i], "all") == 0 ||
613.  			   strncmp(t1->name, players[i], NAMSZ) == 0 ||
614.  			  (players[i][0] == '-' &&
615.  			   players[i][1] == t1->plchar &&
616.  			   players[i][2] == 0) ||
617.  			  (digit(players[i][0]) && rank <= atoi(players[i]))){
618.  #ifdef PERS_IS_UID
619.  			outwithit:
620.  #endif
621.  				if(outflg)
622.  				    (void) outentry(rank, t1, 0);
623.  #ifdef nonsense
624.  				total_score += t1->points;
625.  				if(totcharct < sizeof(totchars)-1)
626.  				    totchars[totcharct++] = t1->plchar;
627.  #endif
628.  				break;
629.  			}
630.  		}
631.  		dealloc_ttentry(t1);
632.  	}
633.  #ifdef nonsense
634.  	totchars[totcharct] = 0;
635.  
636.  	/* We would like to determine whether you're experienced.  However,
637.  	   the information collected here only tells about the scores/roles
638.  	   that got into the topten (top 100?).  We should maintain a
639.  	   .hacklog or something in his home directory. */
640.  	flags.beginner = (total_score < 6000);
641.  	for(i=0; i<6; i++)
642.  	    if(!index(totchars, pl_classes[i])) {
643.  		flags.beginner = 1;
644.  		if(!pl_character[0]) pl_character[0] = pl_classes[i];
645.  		break;
646.  	}
647.  #endif /* nonsense /**/
648.  }
649.  
650.  static int
651.  classmon(plch, fem)
652.  char plch;
653.  boolean fem;
654.  {
655.  	switch (plch) {
656.  		case 'A': return PM_ARCHEOLOGIST;
657.  		case 'B': return PM_BARBARIAN;
658.  		case 'C': return (fem ? PM_CAVEWOMAN : PM_CAVEMAN);
659.  		case 'E': return PM_ELF;
660.  		case 'H': return PM_HEALER;
661.  		case 'F':	/* accept old Fighter class */
662.  		case 'K': return PM_KNIGHT;
663.  		case 'P': return (fem ? PM_PRIESTESS : PM_PRIEST);
664.  		case 'R': return PM_ROGUE;
665.  		case 'N':	/* accept old Ninja class */
666.  		case 'S': return PM_SAMURAI;
667.  #ifdef TOURIST
668.  		case 'T': return PM_TOURIST;
669.  #else
670.  		case 'T': return PM_HUMAN;
671.  #endif
672.  		case 'V': return PM_VALKYRIE;
673.  		case 'W': return PM_WIZARD;
674.  		default: impossible("What weird class is this? (%c)", plch);
675.  			return PM_HUMAN_ZOMBIE;
676.  	}
677.  }
678.  
679.  /*
680.   * Get a random player name and class from the high score list,
681.   * and attach them to an object (for statues or morgue corpses).
682.   */
683.  struct obj *
684.  tt_oname(otmp)
685.  struct obj *otmp;
686.  {
687.  	int rank;
688.  	register int i;
689.  	register struct toptenentry *tt;
690.  	FILE *rfile;
691.  
692.  	if (!otmp) return((struct obj *) 0);
693.  
694.  	rfile = fopen_datafile(RECORD, "r");
695.  	if (!rfile) {
696.  		panic("Cannot open record file!");
697.  	}
698.  
699.  	tt = newttentry();
700.  	rank = rnd(10);
701.  pickentry:
702.  	for(i = rank; i; i--) {
703.  	    readentry(rfile, tt);
704.  	    if(tt->points == 0) break;
705.  	}
706.  
707.  	if(tt->points == 0) {
708.  		if(rank > 1) {
709.  			rank = 1;
710.  			rewind(rfile);
711.  			goto pickentry;
712.  		}
713.  		dealloc_ttentry(tt);
714.  		otmp = (struct obj *) 0;
715.  	} else {
716.  		otmp->corpsenm = classmon(tt->plchar, (tt->sex == 'F'));
717.  		otmp->owt = weight(otmp);
718.  		/* Note: oname() is safe since otmp is first in chains */
719.  		otmp = oname(otmp, tt->name, 0);
720.  		fobj = otmp;
721.  		level.objects[otmp->ox][otmp->oy] = otmp;
722.  		dealloc_ttentry(tt);
723.  	}
724.  
725.  	(void) fclose(rfile);
726.  	return otmp;
727.  }
728.  
729.  #ifdef NO_SCAN_BRACK
730.  /* Lattice scanf isn't up to reading the scorefile.  What */
731.  /* follows deals with that; I admit it's ugly. (KL) */
732.  /* Now generally available (KL) */
733.  static void
734.  nsb_mung_line(p)
735.  	char *p;
736.  	{
737.  	while(p=index(p,' '))*p='|';
738.  }
739.  
740.  static void
741.  nsb_unmung_line(p)
742.  	char *p;
743.  	{
744.  	while(p=index(p,'|'))*p=' ';
745.  }
746.  #endif
747.  
748.  /*topten.c*/