Source:NetHack 3.2.0/topten.c

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

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

1.   /*	SCCS Id: @(#)topten.c	3.2	96/03/10	*/ 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6.    #include "dlb.h"  7.    #ifdef SHORT_FILENAMES 8.   #include "patchlev.h"  9.    #else 10.  #include "patchlevel.h"  11. #endif 12.   13.   #ifdef VMS 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 17.  #endif 18.   19.   /*  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. 24.   */  25.   #ifdef UPDATE_RECORD_IN_PLACE 26.  static long final_fpos; 27.  #endif 28.   29.   #define done_stopprint program_state.stopprint 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.   #if !defined(MICRO) && !defined(MAC) 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, deaths; 50.  	int ver_major, ver_minor, patchlevel; 51.  	char deathdate[7], birthdate[7]; 52.  	int uid; 53.  	char plchar; 54.  	char sex; 55.  	char name[NAMSZ+1]; 56.  	char death[DTHSZ+1]; 57.  } *tt_head; 58.   59.   static void FDECL(topten_print, (const char *)); 60.  static void FDECL(topten_print_bold, (const char *)); 61.  static xchar FDECL(observable_depth, (d_level *)); 62.  static void NDECL(outheader); 63.  static void FDECL(outentry, (int,struct toptenentry *,BOOLEAN_P)); 64.  static void FDECL(readentry, (FILE *,struct toptenentry *)); 65.  static void FDECL(writeentry, (FILE *,struct toptenentry *)); 66.  static void FDECL(free_ttlist, (struct toptenentry *)); 67.  static int FDECL(classmon, (CHAR_P,BOOLEAN_P)); 68.  static int FDECL(score_wanted,  69.   		(BOOLEAN_P, int,struct toptenentry *,int,const char **,int)); 70.  #ifdef NO_SCAN_BRACK 71.  static void FDECL(nsb_mung_line,(char*)); 72.  static void FDECL(nsb_unmung_line,(char*)); 73.  #endif 74.   75.   /* must fit with end.c; used in rip.c */ 76.  NEARDATA const char *killed_by_prefix[] = { 77.  	"killed by ", "choked on ", "poisoned by ", "", "drowned in ", 78.  	"", "dissolved in ", "crushed to death by ", "petrified by ", "", 79.  	"", "",  80.   	"", "", ""  81.   };  82.    83.   static winid toptenwin = WIN_ERR; 84.   85.   static void 86.  topten_print(x) 87.  const char *x; 88.  {  89.   	if (toptenwin == WIN_ERR) 90.  	    raw_print(x); 91.  	else 92.  	    putstr(toptenwin, ATR_NONE, x); 93.  }  94.    95.   static void 96.  topten_print_bold(x) 97.  const char *x; 98.  {  99.   	if (toptenwin == WIN_ERR) 100. 	    raw_print_bold(x); 101. 	else 102. 	    putstr(toptenwin, ATR_BOLD, x); 103. }  104.   105.  static xchar 106. observable_depth(lev) 107. d_level *lev; 108. {  109.  #if 0	/* if we ever randomize the order of the elemental planes, we  110. must use a constant external representation in the record file */ 111. 	if (In_endgame(lev)) { 112. 	    if (Is_astralevel(lev))	 return -5; 113. 	    else if (Is_waterlevel(lev)) return -4; 114. 	    else if (Is_firelevel(lev))	 return -3; 115. 	    else if (Is_airlevel(lev))	 return -2; 116. 	    else if (Is_earthlevel(lev)) return -1; 117. 	    else			 return 0;	/* ? */ 118.  	} else 119. #endif 120. 	    return depth(lev); 121. }  122.   123.  static void 124. readentry(rfile,tt) 125. FILE *rfile; 126. struct toptenentry *tt; 127. {  128.  #ifdef UPDATE_RECORD_IN_PLACE 129. 	/* note: fscanf below must read the record's terminating newline */ 130. 	final_fpos = tt->fpos = ftell(rfile); 131. #endif 132. #define TTFIELDS 17 133. #ifdef NO_SCAN_BRACK 134. 	if(fscanf(rfile,"%d %d %d %ld %d %d %d %d %d %d %6s %6s %d%*c%c%c %s %s%*c", 135. #else 136. 	if(fscanf(rfile, "%d.%d.%d %ld %d %d %d %d %d %d %6s %6s %d %c%c %[^,],%[^\n]%*c", 137. #endif 138. 			&tt->ver_major, &tt->ver_minor, &tt->patchlevel, 139. 			&tt->points, &tt->deathdnum, &tt->deathlev, 140. 			&tt->maxlvl, &tt->hp, &tt->maxhp, &tt->deaths, 141. 			tt->deathdate, tt->birthdate, 142. 			&tt->uid, &tt->plchar, &tt->sex, 143. 			tt->name, tt->death) != TTFIELDS) 144. #undef TTFIELDS 145. 		tt->points = 0; 146. 	else { 147. #ifdef NO_SCAN_BRACK 148. 		if(tt->points > 0) { 149. 			nsb_unmung_line(tt->name); 150. 			nsb_unmung_line(tt->death); 151. 		}  152.  #endif 153. 	}  154.  }  155.   156.  static void 157. writeentry(rfile,tt) 158. FILE *rfile; 159. struct toptenentry *tt; 160. {  161.  #ifdef NO_SCAN_BRACK 162. 	nsb_mung_line(tt->name); 163. 	nsb_mung_line(tt->death); 164. 	(void) fprintf(rfile,"%d %d %d %ld %d %d %d %d %d %d %6s %6s %d %c%c %s %s\n",  165.  #else  166.  	(void) fprintf(rfile,"%d.%d.%d %ld %d %d %d %d %d %d %6s %6s %d %c%c %s,%s\n", 167. #endif 168. 		tt->ver_major, tt->ver_minor, tt->patchlevel, 169. 		tt->points, tt->deathdnum, tt->deathlev, 170. 		tt->maxlvl, tt->hp, tt->maxhp, tt->deaths, 171. 		tt->deathdate, tt->birthdate, 172. 		tt->uid, tt->plchar, tt->sex, 173. 		onlyspace(tt->name) ? "_" : tt->name, tt->death); 174.  #ifdef NO_SCAN_BRACK  175.  	nsb_unmung_line(tt->name);  176.  	nsb_unmung_line(tt->death);  177.  #endif  178.  }  179.   180.  static void  181.  free_ttlist(tt)  182.  struct toptenentry *tt;  183.  {  184.  	struct toptenentry *ttnext;  185.   186.  	while (tt->points > 0) {  187.  		ttnext = tt->tt_next;  188.  		dealloc_ttentry(tt);  189.  		tt = ttnext;  190.  	}  191.  	dealloc_ttentry(tt);  192.  }  193.   194.  void  195.  topten(how)  196.  int how;  197.  {  198.  	int uid = getuid;  199.  	int rank, rank0 = -1, rank1 = 0;  200.  	int occ_cnt = PERSMAX;  201.  	register struct toptenentry *t0, *tprev;  202.  	struct toptenentry *t1;  203.  	FILE *rfile;  204.  	register int flg = 0;  205.  	boolean t0_used;  206.  #ifdef LOGFILE  207.  	FILE *lfile;  208.  #endif /* LOGFILE */  209.   210.  /* Under DICE 3.0, this crashes the system consistently, apparently due to  211. * corruption of *rfile somewhere. Until I figure this out, just cut out 212.  * topten support entirely - at least then the game exits cleanly. --AC 213.  */  214.  #ifdef _DCC 215. 	return; 216. #endif 217.  218.  	if (flags.toptenwin) { 219. 	    toptenwin = create_nhwindow(NHW_TEXT); 220. 	}  221.   222.  #if defined(UNIX) || defined(VMS) 223. #define HUP	if (!program_state.done_hup) 224. #else 225. #define HUP 226. #endif 227.  228.  #ifdef TOS 229. 	restore_colors;	/* make sure the screen is black on white */ 230. #endif 231. 	/* create a new 'topten' entry */ 232. 	t0 = newttentry; 233. 	/* deepest_lev_reached is in terms of depth, and reporting the 234. 	 * deepest level reached in the dungeon death occurred in doesn't  235. * seem right, so we have to report the death level in depth terms 236. 	 * as well (which also seems reasonable since that's all the player  237.  	 * sees on the screen anyway) 238. 	 */  239.  	t0->ver_major = VERSION_MAJOR; 240. 	t0->ver_minor = VERSION_MINOR; 241. 	t0->patchlevel = PATCHLEVEL; 242. 	t0->points = u.urexp; 243. 	t0->deathdnum = u.uz.dnum; 244. 	t0->deathlev = observable_depth(&u.uz); 245. 	t0->maxlvl = deepest_lev_reached(TRUE); 246. 	t0->hp = u.uhp; 247. 	t0->maxhp = u.uhpmax; 248. 	t0->deaths = u.umortality; 249. 	t0->uid = uid; 250. 	t0->plchar = pl_character[0]; 251. 	t0->sex = (flags.female ? 'F' : 'M'); 252. 	(void) strncpy(t0->name, plname, NAMSZ); 253. 	t0->name[NAMSZ] = '\0'; 254. 	t0->death[0] = '\0'; 255. 	switch (killer_format) { 256. 		default: impossible("bad killer format?"); 257. 		case KILLED_BY_AN: 258. 			Strcat(t0->death, killed_by_prefix[how]); 259. 			(void) strncat(t0->death, an(killer),  260.  						DTHSZ-strlen(t0->death)); 261. 			break; 262. 		case KILLED_BY: 263. 			Strcat(t0->death, killed_by_prefix[how]); 264. 			(void) strncat(t0->death, killer,  265.  						DTHSZ-strlen(t0->death)); 266. 			break; 267. 		case NO_KILLER_PREFIX: 268. 			(void) strncat(t0->death, killer, DTHSZ); 269. 			break; 270. 	}  271.  	Strcpy(t0->birthdate, yymmdd(u.ubirthday)); 272. 	Strcpy(t0->deathdate, yymmdd(0L)); 273. 	t0->tt_next = 0; 274. #ifdef UPDATE_RECORD_IN_PLACE 275. 	t0->fpos = -1L; 276. #endif 277.  278.  #ifdef LOGFILE		/* used for debugging (who dies of what, where) */ 279. 	if (lock_file(LOGFILE, 10)) { 280. 	    if(!(lfile = fopen_datafile(LOGFILE,"a"))) { 281. 		HUP raw_print("Cannot open log file!"); 282. 	    } else { 283. 		writeentry(lfile, t0); 284. 		(void) fclose(lfile); 285. 	    }  286.  	    unlock_file(LOGFILE); 287. 	}  288.  #endif /* LOGFILE */ 289.  290.  	if (wizard || discover) { 291. 	    if (how != PANICKED) HUP { 292. 		char pbuf[BUFSZ]; 293. 		topten_print(""); 294. 		Sprintf(pbuf,  295.  	      "Since you were in %s mode, the score list will not be checked.",  296.  		    wizard ? "wizard" : "discover"); 297. 		topten_print(pbuf); 298. 	    }  299.  	    dealloc_ttentry(t0); 300. 	    goto showwin; 301. 	}  302.   303.  	if (!lock_file(RECORD, 60)) 304. 		goto destroywin; 305.  306.  #ifdef UPDATE_RECORD_IN_PLACE 307. 	rfile = fopen_datafile(RECORD, "r+"); 308. #else 309. 	rfile = fopen_datafile(RECORD, "r"); 310. #endif 311.  312.  	if (!rfile) { 313. 		HUP raw_print("Cannot open record file!"); 314. 		unlock_file(RECORD); 315. 		dealloc_ttentry(t0); 316. 		goto destroywin; 317. 	}  318.   319.  	HUP topten_print(""); 320.  321.  	/* assure minimum number of points */ 322. 	if(t0->points < POINTSMIN) t0->points = 0; 323.  324.  	t1 = tt_head = newttentry; 325. 	tprev = 0; 326. 	t0_used = FALSE; 327. 	/* rank0: -1 undefined, 0 not_on_list, n n_th on list */ 328. 	for(rank = 1; ; ) { 329. 	    readentry(rfile, t1); 330. 	    if (t1->points < POINTSMIN) t1->points = 0; 331. 	    if(rank0 < 0 && t1->points < t0->points) { 332. 		rank0 = rank++; 333. 		if(tprev == 0) 334. 			tt_head = t0; 335. 		else 336. 			tprev->tt_next = t0; 337. 		t0->tt_next = t1; 338. #ifdef UPDATE_RECORD_IN_PLACE 339. 		t0->fpos = t1->fpos;	/* insert here */ 340. #endif 341. 		t0_used = TRUE; 342. 		occ_cnt--; 343. 		flg++;		/* ask for a rewrite */ 344. 	    } else tprev = t1; 345.  346.  	    if(t1->points == 0) break; 347. 	    if(  348.  #ifdef PERS_IS_UID  349.  		t1->uid == t0->uid &&  350.  #else  351.  		strncmp(t1->name, t0->name, NAMSZ) == 0 &&  352.  #endif  353.  		t1->plchar == t0->plchar && --occ_cnt <= 0) { 354. 		    if(rank0 < 0) { 355. 			rank0 = 0; 356. 			rank1 = rank; 357. 			HUP { 358. 			    char pbuf[BUFSZ]; 359. 			    Sprintf(pbuf,  360.  			  "You didn't beat your previous score of %ld points.",  361.  				    t1->points); 362. 			    topten_print(pbuf); 363. 			    topten_print(""); 364. 			}  365.  		    }  366.  		    if(occ_cnt < 0) { 367. 			flg++; 368. 			continue; 369. 		    }  370.  		}  371.  	    if(rank <= ENTRYMAX) { 372. 		t1 = t1->tt_next = newttentry; 373. 		rank++; 374. 	    }  375.  	    if(rank > ENTRYMAX) { 376. 		t1->points = 0; 377. 		break; 378. 	    }  379.  	}  380.  	if(flg) {	/* rewrite record file */ 381. #ifdef UPDATE_RECORD_IN_PLACE 382. 		(void) fseek(rfile, (t0->fpos >= 0 ? 383. 				     t0->fpos : final_fpos), SEEK_SET); 384. #else 385. 		(void) fclose(rfile); 386. 		if(!(rfile = fopen_datafile(RECORD,"w"))){ 387. 			HUP raw_print("Cannot write record file"); 388. 			unlock_file(RECORD); 389. 			free_ttlist(tt_head); 390. 			if (!t0_used) dealloc_ttentry(t0); 391. 			goto destroywin; 392. 		}  393.  #endif	/* UPDATE_RECORD_IN_PLACE */ 394. 		if(!done_stopprint) if(rank0 > 0){ 395. 		    if(rank0 <= 10) 396. 			topten_print("You made the top ten list!"); 397. 		    else { 398. 			char pbuf[BUFSZ]; 399. 			Sprintf(pbuf,  400.  			  "You reached the %d%s place on the top %d list.",  401.  				rank0, ordin(rank0), ENTRYMAX); 402. 			topten_print(pbuf); 403. 		    }  404.  		    topten_print(""); 405. 		}  406.  	}  407.  	if(rank0 == 0) rank0 = rank1; 408. 	if(rank0 <= 0) rank0 = rank; 409. 	if(!done_stopprint) outheader; 410. 	t1 = tt_head; 411. 	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { 412. 	    if(flg  413.  #ifdef UPDATE_RECORD_IN_PLACE  414.  		    && rank >= rank0  415.  #endif  416.  		) writeentry(rfile, t1); 417. 	    if (done_stopprint) continue; 418. 	    if (rank > flags.end_top &&  419.  		    (rank < rank0 - flags.end_around || 420. 		     rank > rank0 + flags.end_around) &&  421.  		    (!flags.end_own || 422. #ifdef PERS_IS_UID 423. 					t1->uid != t0->uid 424. #else 425. 					strncmp(t1->name, t0->name, NAMSZ) 426. #endif 427. 		)) continue; 428. 	    if (rank == rank0 - flags.end_around &&  429.  		    rank0 > flags.end_top + flags.end_around + 1 &&  430.  		    !flags.end_own) 431. 		topten_print(""); 432. 	    if(rank != rank0) 433. 		outentry(rank, t1, FALSE); 434. 	    else if(!rank1) 435. 		outentry(rank, t1, TRUE); 436. 	    else { 437. 		outentry(rank, t1, TRUE); 438. 		outentry(0, t0, TRUE); 439. 	    }  440.  	}  441.  	if(rank0 >= rank) if(!done_stopprint) 442. 		outentry(0, t0, TRUE); 443. #ifdef UPDATE_RECORD_IN_PLACE 444. 	if (flg) { 445. # ifdef TRUNCATE_FILE 446. 		/* if a reasonable way to truncate a file exists, use it */ 447. 		truncate_file(rfile); 448. # else 449. 		/* use sentinel record rather than relying on truncation */ 450. 		t0->points = 0L;	/* terminates file when read back in */ 451. 		t0->ver_major = t0->ver_minor = t0->patchlevel = 0; 452. 		t0->uid = t0->deathdnum = t0->deathlev = 0; 453. 		t0->maxlvl = t0->hp = t0->maxhp = t0->deaths = 0; 454. 		t0->plchar = t0->sex = '-'; 455. 		Strcpy(t0->birthdate, strcpy(t0->deathdate, yymmdd(0L))); 456. 		Strcpy(t0->name, "@"); 457. 		Strcpy(t0->death, " \n"); 458. 		writeentry(rfile, t0); 459. 		(void) fflush(rfile); 460. # endif	/* TRUNCATE_FILE */ 461. 	}  462.  #endif	/* UPDATE_RECORD_IN_PLACE */ 463. 	(void) fclose(rfile); 464. 	unlock_file(RECORD); 465. 	free_ttlist(tt_head); 466. 	if (!t0_used) dealloc_ttentry(t0); 467.  468.    showwin: 469. 	if (flags.toptenwin && !done_stopprint) display_nhwindow(toptenwin, 1); 470.   destroywin: 471. 	if (flags.toptenwin) { 472. 	    destroy_nhwindow(toptenwin); 473. 	    toptenwin=WIN_ERR; 474. 	}  475.  }  476.   477.  static void 478. outheader 479. {  480.  	char linebuf[BUFSZ]; 481. 	register char *bp; 482.  483.  	Strcpy(linebuf, " No  Points     Name"); 484. 	bp = eos(linebuf); 485. 	while(bp < linebuf + COLNO - 9) *bp++ = ' '; 486. 	Strcpy(bp, "Hp [max]"); 487. 	topten_print(linebuf); 488. }  489.   490.  /* so>0: standout line; so=0: ordinary line */ 491. static void 492. outentry(rank, t1, so) 493. struct toptenentry *t1; 494. int rank; 495. boolean so; 496. {  497.  	boolean second_line = TRUE; 498. 	char linebuf[BUFSZ]; 499. 	char *bp, hpbuf[24], linebuf3[BUFSZ]; 500. 	int hppos, lngr; 501.  502.   503.  	linebuf[0] = '\0'; 504. 	if (rank) Sprintf(eos(linebuf), "%3d", rank); 505. 	else Strcat(linebuf, "   "); 506.  507.  	Sprintf(eos(linebuf), " %10ld  %.10s", t1->points, t1->name); 508. 	Sprintf(eos(linebuf), "-%c ", t1->plchar); 509. 	if (!strncmp("escaped", t1->death, 7)) { 510. 	    second_line = FALSE; 511. 	    if (!strcmp(" (with the Amulet)", t1->death + 7)) 512. 		Strcat(linebuf, "escaped the dungeon with the Amulet"); 513. 	    else 514. 		Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",  515.  			t1->maxlvl); 516. 	} else if (!strncmp("ascended", t1->death, 8)) { 517. 	    Sprintf(eos(linebuf), "ascended to demigod%s-hood",  518.  		    (t1->sex == 'F') ? "dess" : ""); 519. 	    second_line = FALSE; 520. 	} else { 521. 	    if (!strncmp(t1->death, "quit", 4)) { 522. 		Strcat(linebuf, "quit"); 523. 		second_line = FALSE; 524. 	    } else if (!strncmp(t1->death, "starv", 5)) { 525. 		Strcat(linebuf, "starved to death"); 526. 		second_line = FALSE; 527. 	    } else if (!strncmp(t1->death, "choked", 6)) { 528. 		Sprintf(eos(linebuf), "choked on h%s food",  529.  			(t1->sex == 'F') ? "er" : "is"); 530. 	    } else if (!strncmp(t1->death, "poisoned", 8)) { 531. 		Strcat(linebuf, "was poisoned"); 532. 	    } else if (!strncmp(t1->death, "crushed", 7)) { 533. 		Strcat(linebuf, "was crushed to death"); 534. 	    } else if (!strncmp(t1->death, "petrified by ", 13)) { 535. 		Strcat(linebuf, "turned to stone"); 536. 	    } else Strcat(linebuf, "died"); 537.  538.  	    if (t1->deathdnum == astral_level.dnum) { 539. 		const char *arg, *fmt = " on the Plane of %s"; 540.  541.  		switch (t1->deathlev) { 542. 		case -5: 543. 			fmt = " on the %s Plane"; 544. 			arg = "Astral";	break; 545. 		case -4: 546. 			arg = "Water";	break; 547. 		case -3: 548. 			arg = "Fire";	break; 549. 		case -2: 550. 			arg = "Air";	break; 551. 		case -1: 552. 			arg = "Earth";	break; 553. 		default: 554. 			arg = "Void";	break; 555. 		}  556.  		Sprintf(eos(linebuf), fmt, arg); 557. 	    } else { 558. 		Sprintf(eos(linebuf), " in %s on level %d",  559.  			dungeons[t1->deathdnum].dname, t1->deathlev); 560. 		if (t1->deathlev != t1->maxlvl) 561. 		    Sprintf(eos(linebuf), " [max %d]", t1->maxlvl); 562. 	    }  563.   564.  	    /* kludge for "quit while already on Charon's boat" */ 565. 	    if (!strncmp(t1->death, "quit ", 5)) 566. 		Strcat(linebuf, t1->death + 4); 567. 	}  568.  	Strcat(linebuf, "."); 569.  570.  	/* Quit, starved, ascended, and escaped contain no second line */ 571. 	if (second_line) 572. 	    Sprintf(eos(linebuf), "  %c%s.", highc(*(t1->death)), t1->death+1); 573.  574.  	lngr = (int)strlen(linebuf); 575. 	if (t1->hp <= 0) hpbuf[0] = '-', hpbuf[1] = '\0'; 576. 	else Sprintf(hpbuf, "%d", t1->hp); 577. 	/* beginning of hp column after padding (not actually padded yet) */ 578. 	hppos = COLNO - (sizeof("  Hp [max]")-1); /* sizeof(str) includes \0 */ 579. 	while (lngr >= hppos) { 580. 	    for(bp = eos(linebuf);  581.  		    !(*bp == ' ' && (bp-linebuf < hppos));  582.  		    bp--) 583. 		;  584.  	    Strcpy(linebuf3, bp+1); 585. 	    *bp = 0; 586. 	    if (so) { 587. 		while (bp < linebuf + (COLNO-1)) *bp++ = ' '; 588. 		*bp = 0; 589. 		topten_print_bold(linebuf); 590. 	    } else 591. 		topten_print(linebuf); 592. 	    Sprintf(linebuf, "%15s %s", "", linebuf3); 593. 	    lngr = strlen(linebuf); 594. 	}  595.  	/* beginning of hp column not including padding */ 596. 	hppos = COLNO - 7 - (int)strlen(hpbuf); 597. 	bp = eos(linebuf); 598.  599.  	if (bp <= linebuf + hppos) { 600. 	    /* pad any necessary blanks to the hit point entry */ 601. 	    while (bp < linebuf + hppos) *bp++ = ' '; 602. 	    Strcpy(bp, hpbuf); 603. 	    Sprintf(eos(bp), " %s[%d]",  604.  		    (t1->maxhp < 10) ? "  " : (t1->maxhp < 100) ? " " : "",  605.  		    t1->maxhp); 606. 	}  607.   608.  	if (so) { 609. 	    bp = eos(linebuf); 610. 	    if (so >= COLNO) so = COLNO-1; 611. 	    while (bp < linebuf + so) *bp++ = ' '; 612. 	    *bp = 0; 613. 	    topten_print_bold(linebuf); 614. 	} else 615. 	    topten_print(linebuf); 616. }  617.   618.  static int 619. score_wanted(current_ver, rank, t1, playerct, players, uid) 620. boolean current_ver; 621. int rank; 622. struct toptenentry *t1; 623. int playerct; 624. const char **players; 625. int uid; 626. {  627.  	int i;  628. 629. 	if (current_ver && (t1->ver_major != VERSION_MAJOR || 630. 			    t1->ver_minor != VERSION_MINOR || 631. 			    t1->patchlevel != PATCHLEVEL)) 632. 		return 0; 633.  634.  #ifdef PERS_IS_UID 635. 	if (!playerct && t1->uid == uid) 636. 		return 1; 637. #endif 638.  639.  	for (i = 0; i < playerct; i++) { 640. 		if (strcmp(players[i], "all") == 0 ||  641.  		    strncmp(t1->name, players[i], NAMSZ) == 0 ||  642.  		    (players[i][0] == '-' && 643. 		     players[i][1] == t1->plchar && 644. 		     players[i][2] == 0) ||  645.  		    (digit(players[i][0]) && rank <= atoi(players[i]))) 646. 		return 1; 647. 	}  648.  	return 0; 649. }  650.   651.  /*  652.   * print selected parts of score list. 653.  * argc >= 2, with argv[0] untrustworthy (directory names, et al.), 654.  * and argv[1] starting with "-s". 655.  */  656.  void 657. prscore(argc,argv) 658. int argc; 659. char **argv; 660. {  661.  	const char **players; 662. 	int playerct, rank; 663. 	boolean current_ver = TRUE; 664. 	register struct toptenentry *t1; 665. 	FILE *rfile; 666. 	boolean match_found = FALSE; 667. 	register int i;  668. char pbuf[BUFSZ]; 669. 	int uid = -1; 670. #ifndef PERS_IS_UID 671. 	const char *player0; 672. #endif 673. 	if (argc < 2 || strncmp(argv[1], "-s", 2)) { 674. 		raw_printf("prscore: bad arguments (%d)", argc); 675. 		return; 676. 	}  677.   678.  	rfile = fopen_datafile(RECORD, "r"); 679. 	if (!rfile) { 680. 		raw_print("Cannot open record file!"); 681. 		return; 682. 	}  683.   684.  #ifdef	AMIGA 685. 	{  686.  	    extern winid amii_rawprwin; 687. 	    init_nhwindows(&argc, argv); 688. 	    amii_rawprwin = create_nhwindow(NHW_TEXT); 689. 	}  690.  #endif 691.  692.  	/* If the score list isn't after a game, we never went through 693. 	 * initialization. */ 694.  	if (wiz1_level.dlevel == 0) { 695. 		dlb_init; 696. 		init_dungeons; 697. 	}  698.   699.  	if (!argv[1][2]){	/* plain "-s" */ 700. 		argc--; 701. 		argv++; 702. 	} else if (!argv[1][3] && index(pl_classes, argv[1][2])) { 703. 		/* may get this case instead of next accidentally, 704. 		 * but neither is listed in the documentation, so  705. * anything useful that happens is a bonus anyway */ 706. 		argv[1]++; 707. 		argv[1][0] = '-'; 708. 	} else	argv[1] += 2; 709.  710.  	if (argc > 1 && !strcmp(argv[1], "-v")) { 711. 		current_ver = FALSE; 712. 		argc--; 713. 		argv++; 714. 	}  715.   716.  	if (argc <= 1) { 717. #ifdef PERS_IS_UID 718. 		uid = getuid; 719. 		playerct = 0; 720. 		players = (const char **)0; 721. #else 722. 		player0 = plname; 723. 		if (!*player0) 724. # ifdef AMIGA 725. 			player0 = "all";	/* single user system */ 726. # else 727. 			player0 = "hackplayer"; 728. # endif 729. 		playerct = 1; 730. 		players = &player0; 731. #endif 732. 	} else { 733. 		playerct = --argc; 734. 		players = (const char **)++argv; 735. 	}  736.  	raw_print(""); 737.  738.  	t1 = tt_head = newttentry; 739. 	for (rank = 1; ; rank++) { 740. 	    readentry(rfile, t1); 741. 	    if (t1->points == 0) break; 742. 	    if (!match_found &&  743.  		    score_wanted(current_ver, rank, t1, playerct, players, uid)) 744. 		match_found = TRUE; 745. 	    t1 = t1->tt_next = newttentry; 746. 	}  747.  	(void) fclose(rfile); 748. 	if (!match_found) { 749. 	    Sprintf(pbuf, "Cannot find any %sentries for ",  750.  				current_ver ? "current " : ""); 751. 	    if (playerct < 1) Strcat(pbuf, "you."); 752. 	    else { 753. 		    if (playerct > 1) Strcat(pbuf, "any of "); 754. 		    for (i = 0; i < playerct; i++) { 755. 			    Strcat(pbuf, players[i]); 756. 			    if (i < playerct-1) Strcat(pbuf, ":"); 757. 		    }  758.  	    }  759.  	    raw_print(pbuf); 760. 	    raw_printf("Call is: %s -s [-v] [-role] [maxrank] [playernames]",  761.  			 hname); 762. #ifdef	AMIGA 763. 	    display_nhwindow(amii_rawprwin, 1); 764. 	    destroy_nhwindow(amii_rawprwin); 765. 	    amii_rawprwin = WIN_ERR; 766. #endif 767. 	    free_ttlist(tt_head); 768. 	    return; 769. 	}  770.   771.  	outheader; 772. 	t1 = tt_head; 773. 	for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { 774. 	    if (score_wanted(current_ver, rank, t1, playerct, players, uid)) 775. 		(void) outentry(rank, t1, 0); 776. 	}  777.  	free_ttlist(tt_head); 778. #ifdef	AMIGA 779. 	display_nhwindow(amii_rawprwin, 1); 780. 	destroy_nhwindow(amii_rawprwin); 781. 	amii_rawprwin = WIN_ERR; 782. #endif 783. }  784.   785.  static int 786. classmon(plch, fem) 787. char plch; 788. boolean fem; 789. {  790.  	switch (plch) { 791. 		case 'A': return PM_ARCHEOLOGIST; 792. 		case 'B': return PM_BARBARIAN; 793. 		case 'C': return (fem ? PM_CAVEWOMAN : PM_CAVEMAN); 794. 		case 'E': return PM_ELF; 795. 		case 'H': return PM_HEALER; 796. 		case 'F':	/* accept old Fighter class */ 797. 		case 'K': return PM_KNIGHT; 798. 		case 'P': return (fem ? PM_PRIESTESS : PM_PRIEST); 799. 		case 'R': return PM_ROGUE; 800. 		case 'N':	/* accept old Ninja class */ 801. 		case 'S': return PM_SAMURAI; 802. #ifdef TOURIST 803. 		case 'T': return PM_TOURIST; 804. #else 805. 		case 'T': return PM_HUMAN; 806. #endif 807. 		case 'V': return PM_VALKYRIE; 808. 		case 'W': return PM_WIZARD; 809. 		default: impossible("What weird class is this? (%c)", plch); 810. 			return PM_HUMAN_ZOMBIE; 811. 	}  812.  }  813.   814.  /*  815.   * Get a random player name and class from the high score list, 816.  * and attach them to an object (for statues or morgue corpses). 817.  */  818.  struct obj * 819. tt_oname(otmp) 820. struct obj *otmp; 821. {  822.  	int rank; 823. 	register int i;  824. register struct toptenentry *tt; 825. 	FILE *rfile; 826.  827.  	if (!otmp) return((struct obj *) 0); 828.  829.  	rfile = fopen_datafile(RECORD, "r"); 830. 	if (!rfile) { 831. 		panic("Cannot open record file!"); 832. 	}  833.   834.  	tt = newttentry; 835. 	rank = rnd(10); 836. pickentry: 837. 	for(i = rank; i; i--) { 838. 	    readentry(rfile, tt); 839. 	    if(tt->points == 0) break; 840. 	}  841.   842.  	if(tt->points == 0) { 843. 		if(rank > 1) { 844. 			rank = 1; 845. 			rewind(rfile); 846. 			goto pickentry; 847. 		}  848.  		otmp = (struct obj *) 0; 849. 	} else { 850. 		/* reset timer in case corpse started out as lizard or troll */ 851. 		if (otmp->otyp == CORPSE) obj_stop_timers(otmp); 852. 		otmp->corpsenm = classmon(tt->plchar, (tt->sex == 'F')); 853. 		otmp->owt = weight(otmp); 854. 		otmp = oname(otmp, tt->name); 855. 		if (otmp->otyp == CORPSE) start_corpse_timeout(otmp); 856. 	}  857.  	dealloc_ttentry(tt); 858.  859.  	(void) fclose(rfile); 860. 	return otmp; 861. }  862.   863.  #ifdef NO_SCAN_BRACK 864. /* Lattice scanf isn't up to reading the scorefile. What */ 865. /* follows deals with that; I admit it's ugly. (KL) */ 866. /* Now generally available (KL) */ 867. static void 868. nsb_mung_line(p) 869. 	char *p; 870. {  871.  	while ((p = index(p, ' ')) != 0) *p = '|'; 872. }  873.   874.  static void 875. nsb_unmung_line(p) 876. 	char *p; 877. {  878.  	while ((p = index(p, '|')) != 0) *p = ' '; 879. }  880.  #endif /* NO_SCAN_BRACK */ 881.  882.  /*topten.c*/