Source:NetHack 2.3e/topten.c
Jump to navigation
Jump to search
Below is the full text to topten.c from the source code of NetHack 2.3e.
Warning! This is the source code from an old release. For newer releases, see Source code
Screenshots and source code from Hack are used under the CWI license.
1. /* SCCS Id: @(#)topten.c 2.3 88/02/01 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. 4. #include <stdio.h> 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; i<playerct; i++) 453. printf("%s%s", players[i], (i<playerct-1)?", ":".\n"); 454. printf("Call is: %s -s [playernames]\n", hname); 455. } 456. } 457. return; 458. } 459. 460. if(outflg) outheader(); 461. t1 = tt_head; 462. for(rank = 1; t1->points != 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. }