Source:NetHack 3.0.0/topten.c
Jump to navigation
Jump to search
Below is the full text to topten.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.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.0 88/11/24 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /* NetHack may be freely redistributed. See license for details. */ 4. 5. /* block some unused #defines to avoid overloading some cpp's */ 6. #define MONATTK_H 7. #include "hack.h" 8. 9. #include <errno.h> /* George Barbanis */ 10. 11. static char *itoa P((int)), *ordin P((int)); 12. static void outheader(); 13. static int outentry P((int,struct toptenentry *,int)); 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. void 37. topten(){ 38. int uid = getuid(); 39. int rank, rank0 = -1, rank1 = 0; 40. int occ_cnt = PERSMAX; 41. register struct toptenentry *t0, *t1, *tprev; 42. char *recfile = RECORD; 43. #ifdef UNIX 44. char *reclock = "record_lock"; 45. #endif 46. int sleepct = 300; 47. FILE *rfile; 48. register int flg = 0; 49. #ifdef LOGFILE 50. char *lgfile = LOGFILE; 51. FILE *lfile; 52. #ifdef UNIX 53. char *loglock = "logfile_lock"; 54. int sleeplgct = 30; 55. #endif /* UNIX */ 56. #endif /* LOGFILE */ 57. 58. #ifdef MSDOS 59. #define HUP 60. #else 61. #define HUP if(!done_hup) 62. #endif 63. 64. #ifdef UNIX 65. while(link(recfile, reclock) == -1) { 66. HUP perror(reclock); 67. if(!sleepct--) { 68. HUP (void) puts("I give up. Sorry."); 69. HUP (void) puts("Perhaps there is an old record_lock around?"); 70. return; 71. } 72. HUP Printf("Waiting for access to record file. (%d)\n", 73. sleepct); 74. HUP (void) fflush(stdout); 75. #if defined(SYSV) || defined(ULTRIX) 76. (void) 77. #endif 78. sleep(1); 79. } 80. #endif 81. if(!(rfile = fopen(recfile,"r"))){ 82. HUP (void) puts("Cannot open record file!"); 83. goto unlock; 84. } 85. HUP (void) putchar('\n'); 86. 87. /* create a new 'topten' entry */ 88. t0 = newttentry(); 89. t0->level = dlevel; 90. t0->maxlvl = maxdlevel; 91. t0->hp = u.uhp; 92. t0->maxhp = u.uhpmax; 93. t0->points = u.urexp; 94. t0->plchar = pl_character[0]; 95. t0->sex = (flags.female ? 'F' : 'M'); 96. t0->uid = uid; 97. (void) strncpy(t0->name, plname, NAMSZ); 98. (t0->name)[NAMSZ] = 0; 99. (void) strncpy(t0->death, killer, DTHSZ); 100. (t0->death)[DTHSZ] = 0; 101. Strcpy(t0->date, getdate()); 102. 103. /* assure minimum number of points */ 104. if(t0->points < POINTSMIN) t0->points = 0; 105. #ifdef LOGFILE /* used for debugging (who dies of what, where) */ 106. #ifdef UNIX 107. while(link(lgfile, loglock) == -1) { 108. extern int errno; 109. 110. if (errno == ENOENT) /* If no such file, do not keep log */ 111. goto lgend; /* George Barbanis */ 112. HUP perror(loglock); 113. if(!sleeplgct--) { 114. HUP (void) puts("I give up. Sorry."); 115. HUP (void) puts("Perhaps there is an old logfile_lock around?"); 116. goto lgend; 117. } 118. HUP Printf("Waiting for access to log file. (%d)\n", 119. sleeplgct); 120. HUP (void) fflush(stdout); 121. #if defined(SYSV) || defined(ULTRIX) 122. (void) 123. #endif 124. sleep(1); 125. } 126. #endif /* UNIX */ 127. if(!(lfile = fopen(lgfile,"a"))){ 128. HUP (void) puts("Cannot open log file!"); 129. goto lgend; 130. } 131. (void) fprintf(lfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n", 132. t0->date, t0->uid, 133. t0->level, t0->maxlvl, 134. t0->hp, t0->maxhp, t0->points, 135. t0->plchar, t0->sex, t0->name, t0->death); 136. (void) fclose(lfile); 137. #ifdef UNIX 138. (void) unlink(loglock); 139. #endif /* UNIX */ 140. lgend:; 141. #endif /* LOGFILE */ 142. 143. t1 = tt_head = newttentry(); 144. tprev = 0; 145. /* rank0: -1 undefined, 0 not_on_list, n n_th on list */ 146. for(rank = 1; ; ) { 147. #ifdef TOS 148. char k1[2],k2[2]; 149. if(fscanf(rfile, "%6s %d %d %d %d %d %ld %1s%1s %s %s]", 150. #else 151. if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", 152. #endif 153. t1->date, &t1->uid, 154. &t1->level, &t1->maxlvl, 155. &t1->hp, &t1->maxhp, &t1->points, 156. #ifdef TOS 157. k1, k2, 158. #else 159. &t1->plchar, &t1->sex, 160. #endif 161. t1->name, t1->death) != 11 || t1->points < POINTSMIN) 162. t1->points = 0; 163. 164. #ifdef TOS 165. t1->plchar=k1[0]; 166. t1->sex=k2[0]; 167. #endif 168. if(rank0 < 0 && t1->points < t0->points) { 169. rank0 = rank++; 170. if(tprev == 0) 171. tt_head = t0; 172. else 173. tprev->tt_next = t0; 174. t0->tt_next = t1; 175. occ_cnt--; 176. flg++; /* ask for a rewrite */ 177. } else tprev = t1; 178. 179. if(t1->points == 0) break; 180. if( 181. #ifdef PERS_IS_UID 182. t1->uid == t0->uid && 183. #else 184. strncmp(t1->name, t0->name, NAMSZ) == 0 && 185. #endif 186. t1->plchar == t0->plchar && --occ_cnt <= 0) { 187. if(rank0 < 0) { 188. rank0 = 0; 189. rank1 = rank; 190. HUP Printf("You didn't beat your previous score of %ld points.\n\n", 191. t1->points); 192. } 193. if(occ_cnt < 0) { 194. flg++; 195. continue; 196. } 197. } 198. if(rank <= ENTRYMAX) { 199. t1 = t1->tt_next = newttentry(); 200. rank++; 201. } 202. if(rank > ENTRYMAX) { 203. t1->points = 0; 204. break; 205. } 206. } 207. if(flg) { /* rewrite record file */ 208. (void) fclose(rfile); 209. if(!(rfile = fopen(recfile,"w"))){ 210. HUP (void) puts("Cannot write record file\n"); 211. goto unlock; 212. } 213. 214. if(!done_stopprint) if(rank0 > 0){ 215. if(rank0 <= 10) 216. (void) puts("You made the top ten list!\n"); 217. else 218. Printf("You reached the %d%s place on the top %d list.\n\n", 219. rank0, ordin(rank0), ENTRYMAX); 220. } 221. } 222. if(rank0 == 0) rank0 = rank1; 223. if(rank0 <= 0) rank0 = rank; 224. if(!done_stopprint) outheader(); 225. t1 = tt_head; 226. for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { 227. if(flg) (void) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n", 228. t1->date, t1->uid, 229. t1->level, t1->maxlvl, 230. t1->hp, t1->maxhp, t1->points, 231. t1->plchar, t1->sex, t1->name, t1->death); 232. if(done_stopprint) continue; 233. if(rank > flags.end_top && 234. (rank < rank0-flags.end_around || rank > rank0+flags.end_around) 235. && (!flags.end_own || 236. #ifdef PERS_IS_UID 237. t1->uid != t0->uid 238. #else 239. strncmp(t1->name, t0->name, NAMSZ) 240. #endif 241. )) continue; 242. if(rank == rank0-flags.end_around && 243. rank0 > flags.end_top+flags.end_around+1 && 244. !flags.end_own) 245. (void) putchar('\n'); 246. if(rank != rank0) 247. (void) outentry(rank, t1, 0); 248. else if(!rank1) 249. (void) outentry(rank, t1, 1); 250. else { 251. int t0lth = outentry(0, t0, -1); 252. int t1lth = outentry(rank, t1, t0lth); 253. if(t1lth > t0lth) t0lth = t1lth; 254. (void) outentry(0, t0, t0lth); 255. } 256. } 257. if(rank0 >= rank) if(!done_stopprint) 258. (void) outentry(0, t0, 1); 259. (void) fclose(rfile); 260. unlock: ; 261. #ifdef UNIX 262. (void) unlink(reclock); 263. #endif 264. } 265. 266. static void 267. outheader() { 268. char linebuf[BUFSZ]; 269. register char *bp; 270. 271. Strcpy(linebuf, " No Points Name"); 272. bp = eos(linebuf); 273. while(bp < linebuf + COLNO - 9) *bp++ = ' '; 274. Strcpy(bp, "Hp [max]"); 275. (void) puts(linebuf); 276. } 277. 278. /* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */ 279. static int 280. outentry(rank, t1, so) 281. register struct toptenentry *t1; 282. register int rank, so; 283. { 284. register boolean quit = FALSE, iskilled = FALSE, starv = FALSE, 285. isstoned = FALSE; 286. char linebuf[BUFSZ]; 287. linebuf[0] = 0; 288. if(rank) Sprintf(eos(linebuf), " %2d", rank); 289. else Sprintf(eos(linebuf), " "); 290. Sprintf(eos(linebuf), " %7ld %.10s", t1->points, t1->name); 291. Sprintf(eos(linebuf), "-%c ", t1->plchar); 292. if(!strncmp("escaped", t1->death, 7)) { 293. if(!strcmp(" (with amulet)", t1->death+7)) 294. Sprintf(eos(linebuf), "escaped the dungeon with amulet"); 295. else 296. Sprintf(eos(linebuf), "escaped the dungeon [max level %d]", 297. t1->maxlvl); 298. #ifdef ENDGAME 299. } else if(!strncmp("ascended", t1->death, 8)) { 300. Sprintf(eos(linebuf), "ascended to demigod-hood"); 301. #endif 302. } else { 303. if(!strncmp(t1->death,"quit",4)) { 304. quit = TRUE; 305. Sprintf(eos(linebuf), "quit"); 306. } else if(!strcmp(t1->death,"choked")) 307. Sprintf(eos(linebuf), "choked on %s food", 308. (t1->sex == 'F') ? "her" : "his"); 309. else if(!strncmp(t1->death,"starv",5)) { 310. Sprintf(eos(linebuf), "starved to death"); 311. starv = TRUE; 312. } else if(!strncmp(t1->death, "turned to stone by ",19)) { 313. Sprintf(eos(linebuf), "was petrified"); 314. isstoned = TRUE; 315. } else { 316. Sprintf(eos(linebuf), "was killed"); 317. iskilled = TRUE; 318. } 319. #ifdef ENDLEVEL 320. if (t1->level == ENDLEVEL) 321. Strcpy(eos(linebuf), " in the endgame"); 322. else 323. #endif 324. Sprintf(eos(linebuf), " on%s level %d", 325. (iskilled || isstoned || starv) ? "" : " dungeon", t1->level); 326. if(t1->maxlvl != t1->level) 327. Sprintf(eos(linebuf), " [max %d]", t1->maxlvl); 328. if(quit && t1->death[4]) Sprintf(eos(linebuf), t1->death + 4); 329. } 330. if(iskilled) Sprintf(eos(linebuf), " by %s%s", 331. (!strncmp(t1->death, "trick", 5) || !strncmp(t1->death, "the ", 4) 332. || !strncmp(t1->death, "Mr. ", 4) || !strncmp(t1->death, "Ms. ", 4) 333. ) ? "" : 334. index(vowels,*t1->death) ? "an " : "a ", 335. t1->death); 336. if (isstoned) Sprintf(eos(linebuf), " by %s%s", index(vowels, 337. *(t1->death + 19)) ? "an " : "a ", t1->death + 19); 338. Sprintf(eos(linebuf), "."); 339. if(t1->maxhp) { 340. register char *bp = eos(linebuf); 341. char hpbuf[10]; 342. int hppos; 343. int lngr = strlen(linebuf); 344. Sprintf(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-"); 345. hppos = COLNO - 7 - strlen(hpbuf); 346. if (lngr >= hppos) hppos = (2*COLNO) - 7 - strlen(hpbuf); 347. if(bp <= linebuf + hppos) { 348. /* pad any necessary blanks to the hit point entry */ 349. while(bp < linebuf + hppos) *bp++ = ' '; 350. Strcpy(bp, hpbuf); 351. if(t1->maxhp < 10) 352. Sprintf(eos(bp), " [%d]", t1->maxhp); 353. else if(t1->maxhp < 100) 354. Sprintf(eos(bp), " [%d]", t1->maxhp); 355. else Sprintf(eos(bp), " [%d]", t1->maxhp); 356. } 357. } 358. if(so == 0) (void) puts(linebuf); 359. else if(so > 0) { 360. register char *bp = eos(linebuf); 361. if(so >= COLNO) so = COLNO-1; 362. while(bp < linebuf + so) *bp++ = ' '; 363. *bp = 0; 364. standoutbeg(); 365. (void) fputs(linebuf,stdout); 366. standoutend(); 367. (void) putchar('\n'); 368. } 369. return(strlen(linebuf)); 370. } 371. 372. static char * 373. itoa(a) int a; { 374. #ifdef LINT /* static char buf[12]; */ 375. char buf[12]; 376. #else 377. static char buf[12]; 378. #endif 379. Sprintf(buf,"%d",a); 380. return(buf); 381. } 382. 383. static char * 384. ordin(n) 385. int n; { 386. register int dd = n%10; 387. 388. #if ENTRYMAX > 110 389. return((dd==0 || dd>3 || (n/10)%10==1) ? "th" : 390. #else 391. return((dd==0 || dd>3 || n/10==1) ? "th" : 392. #endif 393. (dd==1) ? "st" : (dd==2) ? "nd" : "rd"); 394. } 395. 396. char * 397. eos(s) 398. register char *s; 399. { 400. while(*s) s++; 401. return(s); 402. } 403. 404. /* 405. * Called with args from main if argc >= 0. In this case, list scores as 406. * requested. Otherwise, find scores for the current player (and list them 407. * if argc == -1). 408. */ 409. void 410. prscore(argc,argv) 411. int argc; 412. char **argv; 413. { 414. char **players; 415. int playerct; 416. int rank; 417. register struct toptenentry *t1, *t2; 418. char *recfile = RECORD; 419. FILE *rfile; 420. register int flg = 0, i; 421. #ifdef nonsense 422. long total_score = 0L; 423. char totchars[10]; 424. int totcharct = 0; 425. #endif 426. int outflg = (argc >= -1); 427. #ifdef PERS_IS_UID 428. int uid = -1; 429. #else 430. char *player0; 431. #endif 432. 433. if(!(rfile = fopen(recfile,"r"))){ 434. (void) puts("Cannot open record file!"); 435. return; 436. } 437. 438. if(argc > 1 && !strncmp(argv[1], "-s", 2)){ 439. if(!argv[1][2]){ 440. argc--; 441. argv++; 442. } else if(!argv[1][3] && index("ABCEHKPRSTVW", argv[1][2])) { 443. argv[1]++; 444. argv[1][0] = '-'; 445. } else argv[1] += 2; 446. } 447. if(argc <= 1){ 448. #ifdef PERS_IS_UID 449. uid = getuid(); 450. playerct = 0; 451. #else 452. player0 = plname; 453. if(!*player0) 454. player0 = "hackplayer"; 455. playerct = 1; 456. players = &player0; 457. #endif 458. } else { 459. playerct = --argc; 460. players = ++argv; 461. } 462. if(outflg) (void) putchar('\n'); 463. 464. t1 = tt_head = newttentry(); 465. for(rank = 1; ; rank++) { 466. #ifdef TOS 467. char k1[2], k2[2]; 468. if(fscanf(rfile, "%6s %d %d %d %d %d %ld %1s%1s %s %s]", 469. #else 470. if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", 471. #endif 472. t1->date, &t1->uid, 473. &t1->level, &t1->maxlvl, 474. &t1->hp, &t1->maxhp, &t1->points, 475. #ifdef TOS 476. k1, k2, 477. #else 478. &t1->plchar, &t1->sex, 479. #endif 480. t1->name, t1->death) != 11) 481. t1->points = 0; 482. if(t1->points == 0) break; 483. #ifdef TOS 484. t1->plchar=k1[0]; 485. t1->sex=k2[0]; 486. #endif 487. #ifdef PERS_IS_UID 488. if(!playerct && t1->uid == uid) 489. flg++; 490. else 491. #endif 492. for(i = 0; i < playerct; i++){ 493. if(strcmp(players[i], "all") == 0 || 494. strncmp(t1->name, players[i], NAMSZ) == 0 || 495. (players[i][0] == '-' && 496. players[i][1] == t1->plchar && 497. players[i][2] == 0) || 498. (digit(players[i][0]) && rank <= atoi(players[i]))) 499. flg++; 500. } 501. t1 = t1->tt_next = newttentry(); 502. } 503. (void) fclose(rfile); 504. if(!flg) { 505. if(outflg) { 506. Printf("Cannot find any entries for "); 507. if(playerct < 1) Printf("you.\n"); 508. else { 509. if(playerct > 1) Printf("any of "); 510. for(i=0; i<playerct; i++) 511. Printf("%s%s", players[i], (i<playerct-1)?", ":".\n"); 512. Printf("Call is: %s -s [-role] [maxrank] [playernames]\n", hname); 513. } 514. } 515. return; 516. } 517. 518. if(outflg) outheader(); 519. t1 = tt_head; 520. for(rank = 1; t1->points != 0; rank++, t1 = t2) { 521. t2 = t1->tt_next; 522. #ifdef PERS_IS_UID 523. if(!playerct && t1->uid == uid) 524. goto outwithit; 525. else 526. #endif 527. for(i = 0; i < playerct; i++){ 528. if(strcmp(players[i], "all") == 0 || 529. strncmp(t1->name, players[i], NAMSZ) == 0 || 530. (players[i][0] == '-' && 531. players[i][1] == t1->plchar && 532. players[i][2] == 0) || 533. (digit(players[i][0]) && rank <= atoi(players[i]))){ 534. outwithit: 535. if(outflg) 536. (void) outentry(rank, t1, 0); 537. #ifdef nonsense 538. total_score += t1->points; 539. if(totcharct < sizeof(totchars)-1) 540. totchars[totcharct++] = t1->plchar; 541. #endif 542. break; 543. } 544. } 545. free((genericptr_t) t1); 546. } 547. #ifdef nonsense 548. totchars[totcharct] = 0; 549. 550. /* We would like to determine whether he is experienced. However, 551. the information collected here only tells about the scores/roles 552. that got into the topten (top 100?). We should maintain a 553. .hacklog or something in his home directory. */ 554. flags.beginner = (total_score < 6000); 555. for(i=0; i<6; i++) 556. if(!index(totchars, "ABCEHKPRSTVW"[i])) { 557. flags.beginner = 1; 558. if(!pl_character[0]) pl_character[0] = "ABCEHKPRSTVW"[i]; 559. break; 560. } 561. #endif /* nonsense /**/ 562. } 563. 564. static int 565. classmon(plch, fem) 566. char plch; 567. boolean fem; 568. { 569. switch (plch) { 570. case 'A': return PM_ARCHEOLOGIST; 571. case 'B': return PM_BARBARIAN; 572. case 'C': return (fem ? PM_CAVEWOMAN : PM_CAVEMAN); 573. case 'E': return PM_ELF; 574. case 'H': return PM_HEALER; 575. case 'F': /* accept old Fighter class */ 576. case 'K': return PM_KNIGHT; 577. case 'P': return (fem ? PM_PRIESTESS : PM_PRIEST); 578. case 'R': return PM_ROGUE; 579. case 'N': /* accept old Ninja class */ 580. case 'S': return PM_SAMURAI; 581. case 'T': return PM_TOURIST; 582. case 'V': return PM_VALKYRIE; 583. case 'W': return PM_WIZARD; 584. default: impossible("What weird class is this? (%c)", plch); 585. return PM_HUMAN_ZOMBIE; 586. } 587. } 588. 589. /* 590. * Get a random player name and class from the high score list, 591. * and attach them to an object (for statues or morgue corpses). 592. */ 593. struct obj * 594. tt_oname(otmp) 595. struct obj *otmp; 596. { 597. int rank; 598. register int i; 599. register struct toptenentry *tt; 600. char *recfile = RECORD; 601. FILE *rfile; 602. 603. if (!otmp) return((struct obj *) 0); 604. 605. if(!(rfile = fopen(recfile,"r"))) 606. panic("Cannot open record file!"); 607. 608. tt = newttentry(); 609. rank = rnd(10); 610. pickentry: 611. for(i = rank; i; i--) { 612. #ifdef TOS 613. char k1[2], k2[2]; 614. if(fscanf(rfile, "%6s %d %d %d %d %d %ld %1s%1s %s %s]", 615. #else 616. if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", 617. #endif 618. tt->date, &tt->uid, 619. &tt->level, &tt->maxlvl, 620. &tt->hp, &tt->maxhp, &tt->points, 621. #ifdef TOS 622. k1, k2, 623. #else 624. &tt->plchar, &tt->sex, 625. #endif 626. tt->name, tt->death) != 11) 627. tt->points = 0; 628. if(tt->points == 0) break; 629. #ifdef TOS 630. tt->plchar=k1[0]; 631. tt->sex=k2[0]; 632. #endif 633. } 634. (void) fclose(rfile); 635. 636. if(tt->points == 0) { 637. if(rank > 1) { 638. rank = 1; 639. goto pickentry; 640. } 641. free((genericptr_t) tt); 642. return((struct obj *) 0); 643. } else { 644. otmp->corpsenm = classmon(tt->plchar, (tt->sex == 'F')); 645. otmp->owt = mons[otmp->corpsenm].cwt; 646. otmp = oname(otmp, tt->name, 0); 647. free((genericptr_t) tt); 648. return otmp; 649. } 650. }