Source:NetHack 2.3e/topten.c

Below is the full text to topten.c from the source code of NetHack 2.3e. To link to a particular line, write [[NetHack 2.3e/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	2.3	88/02/01 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.     4.    #include   5.    #include "hack.h"  6.    #ifdef GENIX 7.   #define	void	int	/* jhn - mod to prevent compiler from bombing */ 8.   #endif 9.    10.   #define	Sprintf	(void) sprintf 11.  extern char plname[], pl_character[]; 12.  #ifndef MSC		/* set by the Microsoft "C" compiler */ 13.  extern	char	*itoa; 14.  #endif 15.  extern	char	*ordin, *eos; 16.  extern int done_hup, done_stopprint; 17.   18.   #define newttentry (struct toptenentry *) alloc(sizeof(struct toptenentry)) 19.  #define	NAMSZ	10 20.  #define	DTHSZ	60 21.  #define	PERSMAX	 3		/* entries per name/uid per char. allowed */ 22.  #define	POINTSMIN	1	/* must be > 0 */ 23.  #define	ENTRYMAX	100	/* must be >= 10 */ 24.  #ifndef MSDOS 25.  #define	PERS_IS_UID		/* delete for PERSMAX per name; now per uid */ 26.  #endif 27.  struct toptenentry { 28.  	struct toptenentry *tt_next; 29.  	long int points; 30.  	int level,maxlvl,hp,maxhp; 31.  	int uid; 32.  	char plchar; 33.  	char sex; 34.  	char name[NAMSZ+1]; 35.  	char death[DTHSZ+1]; 36.  	char date[7];		/* yymmdd */ 37.  } *tt_head; 38.   39.   topten{ 40.  	int uid = getuid; 41.  	int rank, rank0 = -1, rank1 = 0; 42.  	int occ_cnt = PERSMAX; 43.  	register struct toptenentry *t0, *t1, *tprev; 44.  	char *recfile = RECORD; 45.  #ifdef UNIX 46.  	char *reclock = "record_lock"; 47.  #endif 48.  	int sleepct = 300; 49.  	FILE *rfile; 50.  	register flg = 0; 51.  	extern char *getdate; 52.  #ifdef LOGFILE 53.  	char *lgfile = LOGFILE; 54.  	FILE *lfile; 55.  	char *loglock = "logfile_lock"; 56.  	int sleeplgct = 30; 57.  #endif 58.   59.   #ifndef DGK 60.  #define	HUP	if(!done_hup) 61.  #else 62.  #define HUP 63.  #endif 64.   65.   #ifdef UNIX 66.  	while(link(recfile, reclock) == -1) { 67.  		HUP perror(reclock); 68.  		if(!sleepct--) { 69.  			HUP puts("I give up. Sorry."); 70.  			HUP puts("Perhaps there is an old record_lock around?"); 71.  			return; 72.  		}  73.   		HUP printf("Waiting for access to record file. (%d)\n",  74.   			sleepct); 75.  		HUP (void) fflush(stdout); 76.  		sleep(1); 77.  	}  78.   #endif 79.  	if(!(rfile = fopen(recfile,"r"))){ 80.  		HUP puts("Cannot open record file!"); 81.  		goto unlock; 82.  	}  83.   	HUP (void) putchar('\n'); 84.   85.   	/* create a new 'topten' entry */ 86.  	t0 = newttentry; 87.  	t0->level = dlevel; 88.  	t0->maxlvl = maxdlevel; 89.  	t0->hp = u.uhp; 90.  	t0->maxhp = u.uhpmax; 91.  	t0->points = u.urexp; 92.  	t0->plchar = pl_character[0]; 93.  	t0->sex = (flags.female ? 'F' : 'M'); 94.  	t0->uid = uid; 95.  	(void) strncpy(t0->name, plname, NAMSZ); 96.  	(t0->name)[NAMSZ] = 0; 97.  	(void) strncpy(t0->death, killer, DTHSZ); 98.  	(t0->death)[DTHSZ] = 0; 99.  	(void) strcpy(t0->date, getdate); 100.  101.  	/* assure minimum number of points */ 102. 	if(t0->points < POINTSMIN) 103. 		t0->points = 0; 104. #ifdef LOGFILE		/* used for debugging (who dies of what, where) */ 105. 	while(link(lgfile, loglock) == -1) { 106. 		HUP perror(loglock); 107. 		if(!sleeplgct--) { 108. 			HUP puts("I give up. Sorry."); 109. 			HUP puts("Perhaps there is an old logfile_lock around?"); 110. 			goto lgend; 111. 		}  112.  		HUP printf("Waiting for access to log file. (%d)\n",  113.   			sleeplgct); 114. 		HUP (void) fflush(stdout); 115. 		sleep(1); 116. 	}  117.  	if(!(lfile = fopen(lgfile,"a"))){ 118. 		HUP puts("Cannot open log file!"); 119. 		goto lgend; 120. 	}  121.  	fprintf(lfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n",  122.  	    t0->date, t0->uid,  123.  	    t0->level, t0->maxlvl,  124.  	    t0->hp, t0->maxhp, t0->points,  125.  	    t0->plchar, t0->sex, t0->name, t0->death); 126. 	fclose(lfile); 127. 	(void) unlink(loglock); 128.       lgend:; 129. #endif 130.  131.  	t1 = tt_head = newttentry; 132. 	tprev = 0; 133. 	/* rank0: -1 undefined, 0 not_on_list, n n_th on list */ 134. 	for(rank = 1; ; ) { 135. 	  if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", 136. 		t1->date, &t1->uid, 137. 		&t1->level, &t1->maxlvl, 138. 		&t1->hp, &t1->maxhp, &t1->points, 139. 		&t1->plchar, &t1->sex, t1->name, t1->death) != 11  140.  	  || t1->points < POINTSMIN) 141. 			t1->points = 0; 142. 	  if(rank0 < 0 && t1->points < t0->points) { 143. 		rank0 = rank++; 144. 		if(tprev == 0) 145. 			tt_head = t0; 146. 		else 147. 			tprev->tt_next = t0; 148. 		t0->tt_next = t1; 149. 		occ_cnt--; 150. 		flg++;		/* ask for a rewrite */ 151. 	  } else 152. 		tprev = t1; 153. 	  if(t1->points == 0) break; 154. 	  if(  155.  #ifdef PERS_IS_UID  156.  	     t1->uid == t0->uid &&  157.  #else  158.  	     strncmp(t1->name, t0->name, NAMSZ) == 0 &&  159.  #endif  160.  	     t1->plchar == t0->plchar && --occ_cnt <= 0){ 161. 		if(rank0 < 0){ 162. 			rank0 = 0; 163. 			rank1 = rank; 164. 	HUP printf("You didn't beat your previous score of %ld points.\n\n",  165.  				t1->points); 166. 		}  167.  		if(occ_cnt < 0){ 168. 			flg++; 169. 			continue; 170. 		}  171.  	  }  172.  	  if(rank <= ENTRYMAX){ 173. 		t1 = t1->tt_next = newttentry; 174. 		rank++; 175. 	  }  176.  	  if(rank > ENTRYMAX){ 177. 		t1->points = 0; 178. 		break; 179. 	  }  180.  	}  181.  	if(flg) {	/* rewrite record file */ 182. 		(void) fclose(rfile); 183. 		if(!(rfile = fopen(recfile,"w"))){ 184. 			HUP puts("Cannot write record file\n"); 185. 			goto unlock; 186. 		}  187.   188.  		if(!done_stopprint) if(rank0 > 0){ 189. 		    if(rank0 <= 10) 190. 			puts("You made the top ten list!\n"); 191. 		    else 192. 		printf("You reached the %d%s place on the top %d list.\n\n",  193.  			rank0, ordin(rank0), ENTRYMAX); 194. 		}  195.  	}  196.  	if(rank0 == 0) rank0 = rank1; 197. 	if(rank0 <= 0) rank0 = rank; 198. 	if(!done_stopprint) outheader; 199. 	t1 = tt_head; 200. 	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { 201. 	  if(flg) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n",  202.  	    t1->date, t1->uid,  203.  	    t1->level, t1->maxlvl,  204.  	    t1->hp, t1->maxhp, t1->points,  205.  	    t1->plchar, t1->sex, t1->name, t1->death); 206. 	  if(done_stopprint) continue; 207. 	  if(rank > flags.end_top &&  208.  	    (rank < rank0-flags.end_around || rank > rank0+flags.end_around)  209.  	    && (!flags.end_own || 210. #ifdef PERS_IS_UID 211. 				  t1->uid != t0->uid 212. #else 213. 				  strncmp(t1->name, t0->name, NAMSZ) 214. #endif 215. 		)) continue; 216. 	  if(rank == rank0-flags.end_around &&  217.  	     rank0 > flags.end_top+flags.end_around+1 &&  218.  	     !flags.end_own) 219. 		(void) putchar('\n'); 220. 	  if(rank != rank0) 221. 		(void) outentry(rank, t1, 0); 222. 	  else if(!rank1) 223. 		(void) outentry(rank, t1, 1); 224. 	  else { 225. 		int t0lth = outentry(0, t0, -1); 226. 		int t1lth = outentry(rank, t1, t0lth); 227. 		if(t1lth > t0lth) t0lth = t1lth; 228. 		(void) outentry(0, t0, t0lth); 229. 	  }  230.  	}  231.  	if(rank0 >= rank) if(!done_stopprint) 232. 		(void) outentry(0, t0, 1); 233. 	(void) fclose(rfile); 234. unlock:	; 235. #ifdef UNIX 236. 	(void) unlink(reclock); 237. #endif 238. }  239.   240.  outheader { 241. char linebuf[BUFSZ]; 242. register char *bp; 243. #ifdef KJSMODS 244. 	(void) strcpy(linebuf, " No  Points    Name"); 245. #else 246. 	(void) strcpy(linebuf, "Number Points  Name"); 247. #endif 248. 	bp = eos(linebuf); 249. 	while(bp < linebuf + COLNO - 9) *bp++ = ' '; 250. 	(void) strcpy(bp, "Hp [max]"); 251. 	puts(linebuf); 252. }  253.   254.  /* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */ 255. int 256. outentry(rank,t1,so) register struct toptenentry *t1; { 257. boolean quit = FALSE, killed = FALSE, starv = FALSE; 258. char linebuf[BUFSZ]; 259. 	linebuf[0] = 0; 260. 	if(rank) Sprintf(eos(linebuf), "%3d", rank); 261. 		else Sprintf(eos(linebuf), "   "); 262. #ifdef KJSMODS 263. 	Sprintf(eos(linebuf), " %7ld %10s", t1->points, t1->name); 264. #else 265. # ifdef DGKMOD 266. 	Sprintf(eos(linebuf), " %6ld %10s", t1->points, t1->name); 267. # else 268. 	Sprintf(eos(linebuf), " %6ld %8s", t1->points, t1->name); 269. # endif 270. #endif 271. 	if(t1->plchar == 'X') Sprintf(eos(linebuf), " "); 272. 	else Sprintf(eos(linebuf), "-%c ", t1->plchar); 273. 	if(!strncmp("escaped", t1->death, 7)) { 274. 	  if(!strcmp(" (with amulet)", t1->death+7)) 275. 	    Sprintf(eos(linebuf), "escaped the dungeon with amulet"); 276. 	  else 277. 	    Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",  278.  	      t1->maxlvl); 279. 	} else { 280. 	  if(!strncmp(t1->death,"quit",4)) { 281. 	    quit = TRUE; 282. #ifndef KJSMODS 283. 	    if(t1->maxhp < 3*t1->hp && t1->maxlvl < 4) 284. 		Sprintf(eos(linebuf), "cravenly gave up"); 285. 	    else 286. #endif 287. 		Sprintf(eos(linebuf), "quit"); 288. 	  }  289.  	  else if(!strcmp(t1->death,"choked")) 290. 	    Sprintf(eos(linebuf), "choked on %s food",  291.  		(t1->sex == 'F') ? "her" : "his"); 292. 	  else if(!strncmp(t1->death,"starv",5)) 293. 	    Sprintf(eos(linebuf), "starved to death"), starv = TRUE; 294. 	  else Sprintf(eos(linebuf), ", killed"), killed = TRUE; 295. 	  Sprintf(eos(linebuf), " on%s level %d",  296.  	    (killed || starv) ? "" : " dungeon", t1->level); 297. 	  if(t1->maxlvl != t1->level) 298. 	    Sprintf(eos(linebuf), " [max %d]", t1->maxlvl); 299. 	  if(quit && t1->death[4]) Sprintf(eos(linebuf), t1->death + 4); 300. 	}  301.  	if(killed) Sprintf(eos(linebuf), " by %s%s",  302.  	  (!strncmp(t1->death, "trick", 5) || !strncmp(t1->death, "the ", 4))  303.  		? "" :  304.  	  index(vowels,*t1->death) ? "an " : "a ",  305.  	  t1->death); 306. 	Sprintf(eos(linebuf), "."); 307. 	if(t1->maxhp) { 308. 	  register char *bp = eos(linebuf); 309. 	  char hpbuf[10]; 310. 	  int hppos; 311. #ifdef KJSMODS 312. 	  int lngr = strlen(linebuf); 313. #endif 314. 	  Sprintf(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-"); 315. 	  hppos = COLNO - 7 - strlen(hpbuf); 316. #ifdef KJSMODS 317. 	  if (lngr >= hppos) hppos = (2*COLNO) - 7 - strlen(hpbuf); 318. #endif 319. 	  if(bp <= linebuf + hppos) { 320. 	    /* pad any necessary blanks to the hit point entry */ 321. 	    while(bp < linebuf + hppos) *bp++ = ' '; 322. 	    (void) strcpy(bp, hpbuf); 323. 	    Sprintf(eos(bp), " [%d]", t1->maxhp); 324. 	  }  325.  	}  326.  	if(so == 0) puts(linebuf); 327. 	else if(so > 0) { 328. 	  register char *bp = eos(linebuf); 329. 	  if(so >= COLNO) so = COLNO-1; 330. 	  while(bp < linebuf + so) *bp++ = ' '; 331. 	  *bp = 0; 332. 	  standoutbeg; 333. 	  fputs(linebuf,stdout); 334. 	  standoutend; 335. 	  (void) putchar('\n'); 336. 	}  337.  	return(strlen(linebuf)); 338. }  339.   340.  char * 341. itoa(a) int a; { 342. static char buf[12]; 343. 	Sprintf(buf,"%d",a); 344. 	return(buf); 345. }  346.   347.  char * 348. ordin(n) int n; { 349. register int d = n%10; 350. 	return((d==0 || d>3 || n/10==1) ? "th" : (d==1) ? "st" :  351.  		(d==2) ? "nd" : "rd"); 352. }  353.   354.  char * 355. eos(s) 356. register char *s; 357. {  358.  	while(*s) s++; 359. 	return(s); 360. }  361.   362.  /*  363.   * Called with args from main if argc >= 0. In this case, list scores as 364. * requested. Otherwise, find scores for the current player (and list them 365.   * if argc == -1). 366.  */  367.  prscore(argc,argv) int argc; char **argv; { 368. 	extern char *hname; 369. 	char **players; 370. 	int playerct; 371. 	int rank; 372. 	register struct toptenentry *t1, *t2; 373. 	char *recfile = RECORD; 374. 	FILE *rfile; 375. 	register flg = 0; 376. 	register int i;  377. #ifdef nonsense 378. 	long total_score = 0L; 379. 	char totchars[10]; 380. 	int totcharct = 0; 381. #endif 382. 	int outflg = (argc >= -1); 383. #ifdef PERS_IS_UID 384. 	int uid = -1; 385. #else 386. 	char *player0; 387. #endif 388.  389.  	if(!(rfile = fopen(recfile,"r"))){ 390. 		puts("Cannot open record file!"); 391. 		return; 392. 	}  393.   394.  	if(argc > 1 && !strncmp(argv[1], "-s", 2)){ 395. 		if(!argv[1][2]){ 396. 			argc--; 397. 			argv++; 398. 		} else if(!argv[1][3] && index("CFKSTWX", argv[1][2])) { 399. 			argv[1]++; 400. 			argv[1][0] = '-'; 401. 		} else	argv[1] += 2; 402. 	}  403.  	if(argc <= 1){ 404. #ifdef PERS_IS_UID 405. 		uid = getuid; 406. 		playerct = 0; 407. #else 408. 		player0 = plname; 409. 		if(!*player0) 410. 			player0 = "hackplayer"; 411. 		playerct = 1; 412. 		players = &player0; 413. #endif 414. 	} else { 415. 		playerct = --argc; 416. 		players = ++argv; 417. 	}  418.  	if(outflg) putchar('\n'); 419.  420.  	t1 = tt_head = newttentry; 421. 	for(rank = 1; ; rank++) { 422. 	  if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", 423. 		t1->date, &t1->uid, 424. 		&t1->level, &t1->maxlvl, 425. 		&t1->hp, &t1->maxhp, &t1->points, 426. 		&t1->plchar, &t1->sex, t1->name, t1->death) != 11) 427. 			t1->points = 0; 428. 	  if(t1->points == 0) break; 429. #ifdef PERS_IS_UID 430. 	  if(!playerct && t1->uid == uid) 431. 		flg++; 432. 	  else 433. #endif 434. 	  for(i = 0; i < playerct; i++){ 435. 		if(strcmp(players[i], "all") == 0 ||  436.  		   strncmp(t1->name, players[i], NAMSZ) == 0 ||  437.  		  (players[i][0] == '-' && 438. 		   players[i][1] == t1->plchar && 439. 		   players[i][2] == 0) ||  440.  		  (digit(players[i][0]) && rank <= atoi(players[i]))) 441. 			flg++; 442. 	  }  443.  	  t1 = t1->tt_next = newttentry; 444. 	}  445.  	(void) fclose(rfile); 446. 	if(!flg) { 447. 	    if(outflg) { 448. 		printf("Cannot find any entries for "); 449. 		if(playerct < 1) printf("you.\n"); 450. 		else { 451. 		  if(playerct > 1) printf("any of "); 452. 		  for(i=0; ipoints != 0; rank++, t1 = t2) { 463. 		t2 = t1->tt_next; 464. #ifdef PERS_IS_UID 465. 		if(!playerct && t1->uid == uid) 466. 			goto outwithit; 467. 		else 468. #endif 469. 		for(i = 0; i < playerct; i++){ 470. 			if(strcmp(players[i], "all") == 0 ||  471.  			   strncmp(t1->name, players[i], NAMSZ) == 0 ||  472.  			  (players[i][0] == '-' && 473. 			   players[i][1] == t1->plchar && 474. 			   players[i][2] == 0) ||  475.  			  (digit(players[i][0]) && rank <= atoi(players[i]))){ 476. 			outwithit: 477. 				if(outflg) 478. 				    (void) outentry(rank, t1, 0); 479. #ifdef nonsense 480. 				total_score += t1->points; 481. 				if(totcharct < sizeof(totchars)-1) 482. 				    totchars[totcharct++] = t1->plchar; 483. #endif 484. 				break; 485. 			}  486.  		}  487.  		free((char *) t1); 488. 	}  489.  #ifdef nonsense 490. 	totchars[totcharct] = 0; 491.  492.  	/* We would like to determine whether he is experienced. However, 493. 	   the information collected here only tells about the scores/roles 494. 	   that got into the topten (top 100?). We should maintain a 495. .hacklog or something in his home directory. */ 496.  	flags.beginner = (total_score < 6000); 497. 	for(i=0; i<6; i++) 498. 	    if(!index(totchars, "CFKSTWX"[i])) { 499. 		flags.beginner = 1; 500. 		if(!pl_character[0]) pl_character[0] = "CFKSTWX"[i]; 501. 		break; 502. 	}  503.  #endif /* nonsense /**/ 504. }