Source:NetHack 2.2a/topten.c

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