Source:NetHack 3.4.3/src/topten.c

From NetHackWiki
(Redirected from Source:Ref/topten)
Jump to: navigation, search

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

Top of file[edit]

  1. /*	SCCS Id: @(#)topten.c	3.4	2000/01/21	*/
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */

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. #include "hack.h"
  2. #include "dlb.h"
  3. #ifdef SHORT_FILENAMES
  4. #include "patchlev.h"
  5. #else
  6. #include "patchlevel.h"
  7. #endif
  8.  
  9. #ifdef VMS
  10. /* We don't want to rewrite the whole file, because that entails	 */
  11. /* creating a new version which requires that the old one be deletable. */
  12. # define UPDATE_RECORD_IN_PLACE
  13. #endif
  14.  
  15. /*
  16. * Updating in place can leave junk at the end of the file in some
  17. * circumstances (if it shrinks and the O.S. doesn't have a straightforward
  18. * way to truncate it).  The trailing junk is harmless and the code
  19. * which reads the scores will ignore it.
  20. */
  21. #ifdef UPDATE_RECORD_IN_PLACE
  22. static long final_fpos;
  23. #endif
  24.  
  25. #define done_stopprint program_state.stopprint
  26.  
  27. #define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
  28. #define dealloc_ttentry(ttent) free((genericptr_t) (ttent))
  29. #define NAMSZ	10
  30. #define DTHSZ	100
  31. #define ROLESZ   3
  32. #define PERSMAX	 3		/* entries per name/uid per char. allowed */
  33. #define POINTSMIN	1	/* must be > 0 */
  34. #define ENTRYMAX	100	/* must be >= 10 */
  35.  
  36. #if !defined(MICRO) && !defined(MAC) && !defined(WIN32)
  37. #define PERS_IS_UID		/* delete for PERSMAX per name; now per uid */
  38. #endif
  39. struct toptenentry {
  40. 	struct toptenentry *tt_next;
  41. #ifdef UPDATE_RECORD_IN_PLACE
  42. 	long fpos;
  43. #endif
  44. 	long points;
  45. 	int deathdnum, deathlev;
  46. 	int maxlvl, hp, maxhp, deaths;
  47. 	int ver_major, ver_minor, patchlevel;
  48. 	long deathdate, birthdate;
  49. 	int uid;
  50. 	char plrole[ROLESZ+1];
  51. 	char plrace[ROLESZ+1];
  52. 	char plgend[ROLESZ+1];
  53. 	char plalign[ROLESZ+1];
  54. 	char name[NAMSZ+1];
  55. 	char death[DTHSZ+1];
  56. } *tt_head;
  57.  
  58. STATIC_DCL void FDECL(topten_print, (const char *));
  59. STATIC_DCL void FDECL(topten_print_bold, (const char *));
  60. STATIC_DCL xchar FDECL(observable_depth, (d_level *));
  61. STATIC_DCL void NDECL(outheader);
  62. STATIC_DCL void FDECL(outentry, (int,struct toptenentry *,BOOLEAN_P));
  63. STATIC_DCL void FDECL(readentry, (FILE *,struct toptenentry *));
  64. STATIC_DCL void FDECL(writeentry, (FILE *,struct toptenentry *));
  65. STATIC_DCL void FDECL(free_ttlist, (struct toptenentry *));
  66. STATIC_DCL int FDECL(classmon, (char *,BOOLEAN_P));
  67. STATIC_DCL int FDECL(score_wanted,
  68. 		(BOOLEAN_P, int,struct toptenentry *,int,const char **,int));
  69. #ifdef NO_SCAN_BRACK
  70. STATIC_DCL void FDECL(nsb_mung_line,(char*));
  71. STATIC_DCL void FDECL(nsb_unmung_line,(char*));
  72. #endif

topten_print[edit]

  1. /* must fit with end.c; used in rip.c */
  2. NEARDATA const char * const killed_by_prefix[] = {
  3. 	"killed by ", "choked on ", "poisoned by ", "died of ", "drowned in ",
  4. 	"burned by ", "dissolved in ", "crushed to death by ", "petrified by ",
  5. 	"turned to slime by ", "killed by ", "", "", "", "", ""
  6. };
  7.  
  8. static winid toptenwin = WIN_ERR;
  9.  
  10. STATIC_OVL void
  11. topten_print(x)
  12. const char *x;
  13. {
  14. 	if (toptenwin == WIN_ERR)
  15. 	    raw_print(x);
  16. 	else
  17. 	    putstr(toptenwin, ATR_NONE, x);
  18. }

topten_print_bold[edit]

  1. STATIC_OVL void
  2. topten_print_bold(x)
  3. const char *x;
  4. {
  5. 	if (toptenwin == WIN_ERR)
  6. 	    raw_print_bold(x);
  7. 	else
  8. 	    putstr(toptenwin, ATR_BOLD, x);
  9. }

observable_depth[edit]

  1. STATIC_OVL xchar
  2. observable_depth(lev)
  3. d_level *lev;
  4. {
  5. #if 0	/* if we ever randomize the order of the elemental planes, we
  6. 	   must use a constant external representation in the record file */
  7. 	if (In_endgame(lev)) {
  8. 	    if (Is_astralevel(lev))	 return -5;
  9. 	    else if (Is_waterlevel(lev)) return -4;
  10. 	    else if (Is_firelevel(lev))	 return -3;
  11. 	    else if (Is_airlevel(lev))	 return -2;
  12. 	    else if (Is_earthlevel(lev)) return -1;
  13. 	    else			 return 0;	/* ? */
  14. 	} else
  15. #endif
  16. 	    return depth(lev);
  17. }

readentry[edit]

  1. STATIC_OVL void
  2. readentry(rfile,tt)
  3. FILE *rfile;
  4. struct toptenentry *tt;
  5. {
  6. #ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
  7. 	static const char fmt[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c";
  8. 	static const char fmt32[] = "%c%c %s %s%*c";
  9. 	static const char fmt33[] = "%s %s %s %s %s %s%*c";
  10. #else
  11. 	static const char fmt[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
  12. 	static const char fmt32[] = "%c%c %[^,],%[^\n]%*c";
  13. 	static const char fmt33[] = "%s %s %s %s %[^,],%[^\n]%*c";
  14. #endif
  15.  
  16. #ifdef UPDATE_RECORD_IN_PLACE
  17. 	/* note: fscanf() below must read the record's terminating newline */
  18. 	final_fpos = tt->fpos = ftell(rfile);
  19. #endif
  20. #define TTFIELDS 13
  21. 	if(fscanf(rfile, fmt,
  22. 			&tt->ver_major, &tt->ver_minor, &tt->patchlevel,
  23. 			&tt->points, &tt->deathdnum, &tt->deathlev,
  24. 			&tt->maxlvl, &tt->hp, &tt->maxhp, &tt->deaths,
  25. 			&tt->deathdate, &tt->birthdate,
  26. 			&tt->uid) != TTFIELDS)
  27. #undef TTFIELDS
  28. 		tt->points = 0;
  29. 	else {
  30. 		/* Check for backwards compatibility */
  31. 		if (tt->ver_major < 3 ||
  32. 				(tt->ver_major == 3 && tt->ver_minor < 3)) {
  33. 			int i;
  34.  
  35. 		    if (fscanf(rfile, fmt32,
  36. 				tt->plrole, tt->plgend,
  37. 				tt->name, tt->death) != 4)
  38. 			tt->points = 0;
  39. 		    tt->plrole[1] = '\0';
  40. 		    if ((i = str2role(tt->plrole)) >= 0)
  41. 			Strcpy(tt->plrole, roles[i].filecode);
  42. 		    Strcpy(tt->plrace, "?");
  43. 		    Strcpy(tt->plgend, (tt->plgend[0] == 'M') ? "Mal" : "Fem");
  44. 		    Strcpy(tt->plalign, "?");
  45. 		} else if (fscanf(rfile, fmt33,
  46. 				tt->plrole, tt->plrace, tt->plgend,
  47. 				tt->plalign, tt->name, tt->death) != 6)
  48. 			tt->points = 0;
  49. #ifdef NO_SCAN_BRACK
  50. 		if(tt->points > 0) {
  51. 			nsb_unmung_line(tt->name);
  52. 			nsb_unmung_line(tt->death);
  53. 		}
  54. #endif
  55. 	}
  56.  
  57. 	/* check old score entries for Y2K problem and fix whenever found */
  58. 	if (tt->points > 0) {
  59. 		if (tt->birthdate < 19000000L) tt->birthdate += 19000000L;
  60. 		if (tt->deathdate < 19000000L) tt->deathdate += 19000000L;
  61. 	}
  62. }

writeentry[edit]

  1. STATIC_OVL void
  2. writeentry(rfile,tt)
  3. FILE *rfile;
  4. struct toptenentry *tt;
  5. {
  6. #ifdef NO_SCAN_BRACK
  7. 	nsb_mung_line(tt->name);
  8. 	nsb_mung_line(tt->death);
  9. 	                   /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
  10. 	(void) fprintf(rfile,"%d %d %d %ld %d %d %d %d %d %d %ld %ld %d ",
  11. #else
  12. 	(void) fprintf(rfile,"%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ",
  13. #endif
  14. 		tt->ver_major, tt->ver_minor, tt->patchlevel,
  15. 		tt->points, tt->deathdnum, tt->deathlev,
  16. 		tt->maxlvl, tt->hp, tt->maxhp, tt->deaths,
  17. 		tt->deathdate, tt->birthdate, tt->uid);
  18. 	if (tt->ver_major < 3 ||
  19. 			(tt->ver_major == 3 && tt->ver_minor < 3))
  20. #ifdef NO_SCAN_BRACK
  21. 		(void) fprintf(rfile,"%c%c %s %s\n",
  22. #else
  23. 		(void) fprintf(rfile,"%c%c %s,%s\n",
  24. #endif
  25. 			tt->plrole[0], tt->plgend[0],
  26. 			onlyspace(tt->name) ? "_" : tt->name, tt->death);
  27. 	else
  28. #ifdef NO_SCAN_BRACK
  29. 		(void) fprintf(rfile,"%s %s %s %s %s %s\n",
  30. #else
  31. 		(void) fprintf(rfile,"%s %s %s %s %s,%s\n",
  32. #endif
  33. 			tt->plrole, tt->plrace, tt->plgend, tt->plalign,
  34. 			onlyspace(tt->name) ? "_" : tt->name, tt->death);
  35.  
  36. #ifdef NO_SCAN_BRACK
  37. 	nsb_unmung_line(tt->name);
  38. 	nsb_unmung_line(tt->death);
  39. #endif
  40. }

free_ttlist[edit]

  1. STATIC_OVL void
  2. free_ttlist(tt)
  3. struct toptenentry *tt;
  4. {
  5. 	struct toptenentry *ttnext;
  6.  
  7. 	while (tt->points > 0) {
  8. 		ttnext = tt->tt_next;
  9. 		dealloc_ttentry(tt);
  10. 		tt = ttnext;
  11. 	}
  12. 	dealloc_ttentry(tt);
  13. }

topten[edit]

  1. void
  2. topten(how)
  3. int how;
  4. {
  5. 	int uid = getuid();
  6. 	int rank, rank0 = -1, rank1 = 0;
  7. 	int occ_cnt = PERSMAX;
  8. 	register struct toptenentry *t0, *tprev;
  9. 	struct toptenentry *t1;
  10. 	FILE *rfile;
  11. 	register int flg = 0;
  12. 	boolean t0_used;
  13. #ifdef LOGFILE
  14. 	FILE *lfile;
  15. #endif /* LOGFILE */
  16.  
  17. /* Under DICE 3.0, this crashes the system consistently, apparently due to
  18. * corruption of *rfile somewhere.  Until I figure this out, just cut out
  19. * topten support entirely - at least then the game exits cleanly.  --AC
  20. */
  21. #ifdef _DCC
  22. 	return;
  23. #endif
  24.  
  25. /* If we are in the midst of a panic, cut out topten entirely.
  26. * topten uses alloc() several times, which will lead to
  27. * problems if the panic was the result of an alloc() failure.
  28. */
  29. 	if (program_state.panicking)
  30. 		return;
  31.  
  32. 	if (flags.toptenwin) {
  33. 	    toptenwin = create_nhwindow(NHW_TEXT);
  34. 	}
  35.  
  36. #if defined(UNIX) || defined(VMS) || defined(__EMX__)
  37. #define HUP	if (!program_state.done_hup)
  38. #else
  39. #define HUP
  40. #endif
  41.  
  42. #ifdef TOS
  43. 	restore_colors();	/* make sure the screen is black on white */
  44. #endif
  45. 	/* create a new 'topten' entry */
  46. 	t0_used = FALSE;
  47. 	t0 = newttentry();
  48. 	/* deepest_lev_reached() is in terms of depth(), and reporting the
  49. 	 * deepest level reached in the dungeon death occurred in doesn't
  50. 	 * seem right, so we have to report the death level in depth() terms
  51. 	 * as well (which also seems reasonable since that's all the player
  52. 	 * sees on the screen anyway)
  53. 	 */
  54. 	t0->ver_major = VERSION_MAJOR;
  55. 	t0->ver_minor = VERSION_MINOR;
  56. 	t0->patchlevel = PATCHLEVEL;
  57. 	t0->points = u.urexp;
  58. 	t0->deathdnum = u.uz.dnum;
  59. 	t0->deathlev = observable_depth(&u.uz);
  60. 	t0->maxlvl = deepest_lev_reached(TRUE);
  61. 	t0->hp = u.uhp;
  62. 	t0->maxhp = u.uhpmax;
  63. 	t0->deaths = u.umortality;
  64. 	t0->uid = uid;
  65. 	(void) strncpy(t0->plrole, urole.filecode, ROLESZ);
  66. 	t0->plrole[ROLESZ] = '\0';
  67. 	(void) strncpy(t0->plrace, urace.filecode, ROLESZ);
  68. 	t0->plrace[ROLESZ] = '\0';
  69. 	(void) strncpy(t0->plgend, genders[flags.female].filecode, ROLESZ);
  70. 	t0->plgend[ROLESZ] = '\0';
  71. 	(void) strncpy(t0->plalign, aligns[1-u.ualign.type].filecode, ROLESZ);
  72. 	t0->plalign[ROLESZ] = '\0';
  73. 	(void) strncpy(t0->name, plname, NAMSZ);
  74. 	t0->name[NAMSZ] = '\0';
  75. 	t0->death[0] = '\0';
  76. 	switch (killer_format) {
  77. 		default: impossible("bad killer format?");
  78. 		case KILLED_BY_AN:
  79. 			Strcat(t0->death, killed_by_prefix[how]);
  80. 			(void) strncat(t0->death, an(killer),
  81. 						DTHSZ-strlen(t0->death));
  82. 			break;
  83. 		case KILLED_BY:
  84. 			Strcat(t0->death, killed_by_prefix[how]);
  85. 			(void) strncat(t0->death, killer,
  86. 						DTHSZ-strlen(t0->death));
  87. 			break;
  88. 		case NO_KILLER_PREFIX:
  89. 			(void) strncat(t0->death, killer, DTHSZ);
  90. 			break;
  91. 	}
  92. 	t0->birthdate = yyyymmdd(u.ubirthday);
  93. 	t0->deathdate = yyyymmdd((time_t)0L);
  94. 	t0->tt_next = 0;
  95. #ifdef UPDATE_RECORD_IN_PLACE
  96. 	t0->fpos = -1L;
  97. #endif
  98.  
  99. #ifdef LOGFILE		/* used for debugging (who dies of what, where) */
  100. 	if (lock_file(LOGFILE, SCOREPREFIX, 10)) {
  101. 	    if(!(lfile = fopen_datafile(LOGFILE, "a", SCOREPREFIX))) {
  102. 		HUP raw_print("Cannot open log file!");
  103. 	    } else {
  104. 		writeentry(lfile, t0);
  105. 		(void) fclose(lfile);
  106. 	    }
  107. 	    unlock_file(LOGFILE);
  108. 	}
  109. #endif /* LOGFILE */
  110.  
  111. 	if (wizard || discover) {
  112. 	    if (how != PANICKED) HUP {
  113. 		char pbuf[BUFSZ];
  114. 		topten_print("");
  115. 		Sprintf(pbuf,
  116. 	      "Since you were in %s mode, the score list will not be checked.",
  117. 		    wizard ? "wizard" : "discover");
  118. 		topten_print(pbuf);
  119. 	    }
  120. 	    goto showwin;
  121. 	}
  122.  
  123. 	if (!lock_file(RECORD, SCOREPREFIX, 60))
  124. 		goto destroywin;
  125.  
  126. #ifdef UPDATE_RECORD_IN_PLACE
  127. 	rfile = fopen_datafile(RECORD, "r+", SCOREPREFIX);
  128. #else
  129. 	rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
  130. #endif
  131.  
  132. 	if (!rfile) {
  133. 		HUP raw_print("Cannot open record file!");
  134. 		unlock_file(RECORD);
  135. 		goto destroywin;
  136. 	}
  137.  
  138. 	HUP topten_print("");
  139.  
  140. 	/* assure minimum number of points */
  141. 	if(t0->points < POINTSMIN) t0->points = 0;
  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. 	    readentry(rfile, t1);
  148. 	    if (t1->points < POINTSMIN) t1->points = 0;
  149. 	    if(rank0 < 0 && t1->points < t0->points) {
  150. 		rank0 = rank++;
  151. 		if(tprev == 0)
  152. 			tt_head = t0;
  153. 		else
  154. 			tprev->tt_next = t0;
  155. 		t0->tt_next = t1;
  156. #ifdef UPDATE_RECORD_IN_PLACE
  157. 		t0->fpos = t1->fpos;	/* insert here */
  158. #endif
  159. 		t0_used = TRUE;
  160. 		occ_cnt--;
  161. 		flg++;		/* ask for a rewrite */
  162. 	    } else tprev = t1;
  163.  
  164. 	    if(t1->points == 0) break;
  165. 	    if(
  166. #ifdef PERS_IS_UID
  167. 		t1->uid == t0->uid &&
  168. #else
  169. 		strncmp(t1->name, t0->name, NAMSZ) == 0 &&
  170. #endif
  171. 		!strncmp(t1->plrole, t0->plrole, ROLESZ) &&
  172. 		--occ_cnt <= 0) {
  173. 		    if(rank0 < 0) {
  174. 			rank0 = 0;
  175. 			rank1 = rank;
  176. 			HUP {
  177. 			    char pbuf[BUFSZ];
  178. 			    Sprintf(pbuf,
  179. 			  "You didn't beat your previous score of %ld points.",
  180. 				    t1->points);
  181. 			    topten_print(pbuf);
  182. 			    topten_print("");
  183. 			}
  184. 		    }
  185. 		    if(occ_cnt < 0) {
  186. 			flg++;
  187. 			continue;
  188. 		    }
  189. 		}
  190. 	    if(rank <= ENTRYMAX) {
  191. 		t1->tt_next = newttentry();
  192. 		t1 = t1->tt_next;
  193. 		rank++;
  194. 	    }
  195. 	    if(rank > ENTRYMAX) {
  196. 		t1->points = 0;
  197. 		break;
  198. 	    }
  199. 	}
  200. 	if(flg) {	/* rewrite record file */
  201. #ifdef UPDATE_RECORD_IN_PLACE
  202. 		(void) fseek(rfile, (t0->fpos >= 0 ?
  203. 				     t0->fpos : final_fpos), SEEK_SET);
  204. #else
  205. 		(void) fclose(rfile);
  206. 		if(!(rfile = fopen_datafile(RECORD, "w", SCOREPREFIX))){
  207. 			HUP raw_print("Cannot write record file");
  208. 			unlock_file(RECORD);
  209. 			free_ttlist(tt_head);
  210. 			goto destroywin;
  211. 		}
  212. #endif	/* UPDATE_RECORD_IN_PLACE */
  213. 		if(!done_stopprint) if(rank0 > 0){
  214. 		    if(rank0 <= 10)
  215. 			topten_print("You made the top ten list!");
  216. 		    else {
  217. 			char pbuf[BUFSZ];
  218. 			Sprintf(pbuf,
  219. 			  "You reached the %d%s place on the top %d list.",
  220. 				rank0, ordin(rank0), ENTRYMAX);
  221. 			topten_print(pbuf);
  222. 		    }
  223. 		    topten_print("");
  224. 		}
  225. 	}
  226. 	if(rank0 == 0) rank0 = rank1;
  227. 	if(rank0 <= 0) rank0 = rank;
  228. 	if(!done_stopprint) outheader();
  229. 	t1 = tt_head;
  230. 	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
  231. 	    if(flg
  232. #ifdef UPDATE_RECORD_IN_PLACE
  233. 		    && rank >= rank0
  234. #endif
  235. 		) writeentry(rfile, t1);
  236. 	    if (done_stopprint) continue;
  237. 	    if (rank > flags.end_top &&
  238. 		    (rank < rank0 - flags.end_around ||
  239. 		     rank > rank0 + flags.end_around) &&
  240. 		    (!flags.end_own ||
  241. #ifdef PERS_IS_UID
  242. 					t1->uid != t0->uid
  243. #else
  244. 					strncmp(t1->name, t0->name, NAMSZ)
  245. #endif
  246. 		)) continue;
  247. 	    if (rank == rank0 - flags.end_around &&
  248. 		    rank0 > flags.end_top + flags.end_around + 1 &&
  249. 		    !flags.end_own)
  250. 		topten_print("");
  251. 	    if(rank != rank0)
  252. 		outentry(rank, t1, FALSE);
  253. 	    else if(!rank1)
  254. 		outentry(rank, t1, TRUE);
  255. 	    else {
  256. 		outentry(rank, t1, TRUE);
  257. 		outentry(0, t0, TRUE);
  258. 	    }
  259. 	}
  260. 	if(rank0 >= rank) if(!done_stopprint)
  261. 		outentry(0, t0, TRUE);
  262. #ifdef UPDATE_RECORD_IN_PLACE
  263. 	if (flg) {
  264. # ifdef TRUNCATE_FILE
  265. 	    /* if a reasonable way to truncate a file exists, use it */
  266. 	    truncate_file(rfile);
  267. # else
  268. 	    /* use sentinel record rather than relying on truncation */
  269. 	    t1->points = 0L;	/* terminates file when read back in */
  270. 	    t1->ver_major = t1->ver_minor = t1->patchlevel = 0;
  271. 	    t1->uid = t1->deathdnum = t1->deathlev = 0;
  272. 	    t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0;
  273. 	    t1->plrole[0] = t1->plrace[0] = t1->plgend[0] = t1->plalign[0] = '-';
  274. 	    t1->plrole[1] = t1->plrace[1] = t1->plgend[1] = t1->plalign[1] = 0;
  275. 	    t1->birthdate = t1->deathdate = yyyymmdd((time_t)0L);
  276. 	    Strcpy(t1->name, "@");
  277. 	    Strcpy(t1->death, "<eod>\n");
  278. 	    writeentry(rfile, t1);
  279. 	    (void) fflush(rfile);
  280. # endif	/* TRUNCATE_FILE */
  281. 	}
  282. #endif	/* UPDATE_RECORD_IN_PLACE */
  283. 	(void) fclose(rfile);
  284. 	unlock_file(RECORD);
  285. 	free_ttlist(tt_head);
  286.  
  287. showwin:
  288. 	if (flags.toptenwin && !done_stopprint) display_nhwindow(toptenwin, 1);
  289. destroywin:
  290. 	if (!t0_used) dealloc_ttentry(t0);
  291. 	if (flags.toptenwin) {
  292. 	    destroy_nhwindow(toptenwin);
  293. 	    toptenwin=WIN_ERR;
  294. 	}
  295. }

outheader[edit]

  1. STATIC_OVL void
  2. outheader()
  3. {
  4. 	char linebuf[BUFSZ];
  5. 	register char *bp;
  6.  
  7. 	Strcpy(linebuf, " No  Points     Name");
  8. 	bp = eos(linebuf);
  9. 	while(bp < linebuf + COLNO - 9) *bp++ = ' ';
  10. 	Strcpy(bp, "Hp [max]");
  11. 	topten_print(linebuf);
  12. }

outentry[edit]

  1. /* so>0: standout line; so=0: ordinary line */
  2. STATIC_OVL void
  3. outentry(rank, t1, so)
  4. struct toptenentry *t1;
  5. int rank;
  6. boolean so;
  7. {
  8. 	boolean second_line = TRUE;
  9. 	char linebuf[BUFSZ];
  10. 	char *bp, hpbuf[24], linebuf3[BUFSZ];
  11. 	int hppos, lngr;
  12.  
  13.  
  14. 	linebuf[0] = '\0';
  15. 	if (rank) Sprintf(eos(linebuf), "%3d", rank);
  16. 	else Strcat(linebuf, "   ");
  17.  
  18. 	Sprintf(eos(linebuf), " %10ld  %.10s", t1->points, t1->name);
  19. 	Sprintf(eos(linebuf), "-%s", t1->plrole);
  20. 	if (t1->plrace[0] != '?')
  21. 		Sprintf(eos(linebuf), "-%s", t1->plrace);
  22. 	/* Printing of gender and alignment is intentional.  It has been
  23. 	 * part of the NetHack Geek Code, and illustrates a proper way to
  24. 	 * specify a character from the command line.
  25. 	 */
  26. 	Sprintf(eos(linebuf), "-%s", t1->plgend);
  27. 	if (t1->plalign[0] != '?')
  28. 		Sprintf(eos(linebuf), "-%s ", t1->plalign);
  29. 	else
  30. 		Strcat(linebuf, " ");
  31. 	if (!strncmp("escaped", t1->death, 7)) {
  32. 	    Sprintf(eos(linebuf), "escaped the dungeon %s[max level %d]",
  33. 		    !strncmp(" (", t1->death + 7, 2) ? t1->death + 7 + 2 : "",
  34. 		    t1->maxlvl);
  35. 	    /* fixup for closing paren in "escaped... with...Amulet)[max..." */
  36. 	    if ((bp = index(linebuf, ')')) != 0)
  37. 		*bp = (t1->deathdnum == astral_level.dnum) ? '\0' : ' ';
  38. 	    second_line = FALSE;
  39. 	} else if (!strncmp("ascended", t1->death, 8)) {
  40. 	    Sprintf(eos(linebuf), "ascended to demigod%s-hood",
  41. 		    (t1->plgend[0] == 'F') ? "dess" : "");
  42. 	    second_line = FALSE;
  43. 	} else {
  44. 	    if (!strncmp(t1->death, "quit", 4)) {
  45. 		Strcat(linebuf, "quit");
  46. 		second_line = FALSE;
  47. 	    } else if (!strncmp(t1->death, "died of st", 10)) {
  48. 		Strcat(linebuf, "starved to death");
  49. 		second_line = FALSE;
  50. 	    } else if (!strncmp(t1->death, "choked", 6)) {
  51. 		Sprintf(eos(linebuf), "choked on h%s food",
  52. 			(t1->plgend[0] == 'F') ? "er" : "is");
  53. 	    } else if (!strncmp(t1->death, "poisoned", 8)) {
  54. 		Strcat(linebuf, "was poisoned");
  55. 	    } else if (!strncmp(t1->death, "crushed", 7)) {
  56. 		Strcat(linebuf, "was crushed to death");
  57. 	    } else if (!strncmp(t1->death, "petrified by ", 13)) {
  58. 		Strcat(linebuf, "turned to stone");
  59. 	    } else Strcat(linebuf, "died");
  60.  
  61. 	    if (t1->deathdnum == astral_level.dnum) {
  62. 		const char *arg, *fmt = " on the Plane of %s";
  63.  
  64. 		switch (t1->deathlev) {
  65. 		case -5:
  66. 			fmt = " on the %s Plane";
  67. 			arg = "Astral";	break;
  68. 		case -4:
  69. 			arg = "Water";	break;
  70. 		case -3:
  71. 			arg = "Fire";	break;
  72. 		case -2:
  73. 			arg = "Air";	break;
  74. 		case -1:
  75. 			arg = "Earth";	break;
  76. 		default:
  77. 			arg = "Void";	break;
  78. 		}
  79. 		Sprintf(eos(linebuf), fmt, arg);
  80. 	    } else {
  81. 		Sprintf(eos(linebuf), " in %s", dungeons[t1->deathdnum].dname);
  82. 		if (t1->deathdnum != knox_level.dnum)
  83. 		    Sprintf(eos(linebuf), " on level %d", t1->deathlev);
  84. 		if (t1->deathlev != t1->maxlvl)
  85. 		    Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
  86. 	    }
  87.  
  88. 	    /* kludge for "quit while already on Charon's boat" */
  89. 	    if (!strncmp(t1->death, "quit ", 5))
  90. 		Strcat(linebuf, t1->death + 4);
  91. 	}
  92. 	Strcat(linebuf, ".");
  93.  
  94. 	/* Quit, starved, ascended, and escaped contain no second line */
  95. 	if (second_line)
  96. 	    Sprintf(eos(linebuf), "  %c%s.", highc(*(t1->death)), t1->death+1);
  97.  
  98. 	lngr = (int)strlen(linebuf);
  99. 	if (t1->hp <= 0) hpbuf[0] = '-', hpbuf[1] = '\0';
  100. 	else Sprintf(hpbuf, "%d", t1->hp);
  101. 	/* beginning of hp column after padding (not actually padded yet) */
  102. 	hppos = COLNO - (sizeof("  Hp [max]")-1); /* sizeof(str) includes \0 */
  103. 	while (lngr >= hppos) {
  104. 	    for(bp = eos(linebuf);
  105. 		    !(*bp == ' ' && (bp-linebuf < hppos));
  106. 		    bp--)
  107. 		;
  108. 	    /* special case: if about to wrap in the middle of maximum
  109. 	       dungeon depth reached, wrap in front of it instead */
  110. 	    if (bp > linebuf + 5 && !strncmp(bp - 5, " [max", 5)) bp -= 5;
  111. 	    Strcpy(linebuf3, bp+1);
  112. 	    *bp = 0;
  113. 	    if (so) {
  114. 		while (bp < linebuf + (COLNO-1)) *bp++ = ' ';
  115. 		*bp = 0;
  116. 		topten_print_bold(linebuf);
  117. 	    } else
  118. 		topten_print(linebuf);
  119. 	    Sprintf(linebuf, "%15s %s", "", linebuf3);
  120. 	    lngr = strlen(linebuf);
  121. 	}
  122. 	/* beginning of hp column not including padding */
  123. 	hppos = COLNO - 7 - (int)strlen(hpbuf);
  124. 	bp = eos(linebuf);
  125.  
  126. 	if (bp <= linebuf + hppos) {
  127. 	    /* pad any necessary blanks to the hit point entry */
  128. 	    while (bp < linebuf + hppos) *bp++ = ' ';
  129. 	    Strcpy(bp, hpbuf);
  130. 	    Sprintf(eos(bp), " %s[%d]",
  131. 		    (t1->maxhp < 10) ? "  " : (t1->maxhp < 100) ? " " : "",
  132. 		    t1->maxhp);
  133. 	}
  134.  
  135. 	if (so) {
  136. 	    bp = eos(linebuf);
  137. 	    if (so >= COLNO) so = COLNO-1;
  138. 	    while (bp < linebuf + so) *bp++ = ' ';
  139. 	    *bp = 0;
  140. 	    topten_print_bold(linebuf);
  141. 	} else
  142. 	    topten_print(linebuf);
  143. }

score_wanted[edit]

  1. STATIC_OVL int
  2. score_wanted(current_ver, rank, t1, playerct, players, uid)
  3. boolean current_ver;
  4. int rank;
  5. struct toptenentry *t1;
  6. int playerct;
  7. const char **players;
  8. int uid;
  9. {
  10. 	int i;
  11.  
  12. 	if (current_ver && (t1->ver_major != VERSION_MAJOR ||
  13. 			    t1->ver_minor != VERSION_MINOR ||
  14. 			    t1->patchlevel != PATCHLEVEL))
  15. 		return 0;
  16.  
  17. #ifdef PERS_IS_UID
  18. 	if (!playerct && t1->uid == uid)
  19. 		return 1;
  20. #endif
  21.  
  22. 	for (i = 0; i < playerct; i++) {
  23. 	    if (players[i][0] == '-' && index("pr", players[i][1]) &&
  24. players[i][2] == 0 && i + 1 < playerct) {
  25. 		char *arg = (char *)players[i + 1];
  26. 		if ((players[i][1] == 'p' &&
  27. 		     str2role(arg) == str2role(t1->plrole)) ||
  28. 		    (players[i][1] == 'r' &&
  29. 		     str2race(arg) == str2race(t1->plrace)))
  30. 		    return 1;
  31. 		i++;
  32. 	    } else if (strcmp(players[i], "all") == 0 ||
  33. 		    strncmp(t1->name, players[i], NAMSZ) == 0 ||
  34. 		    (players[i][0] == '-' &&
  35. 		     players[i][1] == t1->plrole[0] &&
  36. 		     players[i][2] == 0) ||
  37. 		    (digit(players[i][0]) && rank <= atoi(players[i])))
  38. 		return 1;
  39. 	}
  40. 	return 0;
  41. }

prscore[edit]

  1. /*
  2. * print selected parts of score list.
  3. * argc >= 2, with argv[0] untrustworthy (directory names, et al.),
  4. * and argv[1] starting with "-s".
  5. */
  6. void
  7. prscore(argc,argv)
  8. int argc;
  9. char **argv;
  10. {
  11. 	const char **players;
  12. 	int playerct, rank;
  13. 	boolean current_ver = TRUE, init_done = FALSE;
  14. 	register struct toptenentry *t1;
  15. 	FILE *rfile;
  16. 	boolean match_found = FALSE;
  17. 	register int i;
  18. 	char pbuf[BUFSZ];
  19. 	int uid = -1;
  20. #ifndef PERS_IS_UID
  21. 	const char *player0;
  22. #endif
  23.  
  24. 	if (argc < 2 || strncmp(argv[1], "-s", 2)) {
  25. 		raw_printf("prscore: bad arguments (%d)", argc);
  26. 		return;
  27. 	}
  28.  
  29. 	rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
  30. 	if (!rfile) {
  31. 		raw_print("Cannot open record file!");
  32. 		return;
  33. 	}
  34.  
  35. #ifdef	AMIGA
  36. 	{
  37. 	    extern winid amii_rawprwin;
  38. 	    init_nhwindows(&argc, argv);
  39. 	    amii_rawprwin = create_nhwindow(NHW_TEXT);
  40. 	}
  41. #endif
  42.  
  43. 	/* If the score list isn't after a game, we never went through
  44. 	 * initialization. */
  45. 	if (wiz1_level.dlevel == 0) {
  46. 		dlb_init();
  47. 		init_dungeons();
  48. 		init_done = TRUE;
  49. 	}
  50.  
  51. 	if (!argv[1][2]){	/* plain "-s" */
  52. 		argc--;
  53. 		argv++;
  54. 	} else	argv[1] += 2;
  55.  
  56. 	if (argc > 1 && !strcmp(argv[1], "-v")) {
  57. 		current_ver = FALSE;
  58. 		argc--;
  59. 		argv++;
  60. 	}
  61.  
  62. 	if (argc <= 1) {
  63. #ifdef PERS_IS_UID
  64. 		uid = getuid();
  65. 		playerct = 0;
  66. 		players = (const char **)0;
  67. #else
  68. 		player0 = plname;
  69. 		if (!*player0)
  70. # ifdef AMIGA
  71. 			player0 = "all";	/* single user system */
  72. # else
  73. 			player0 = "hackplayer";
  74. # endif
  75. 		playerct = 1;
  76. 		players = &player0;
  77. #endif
  78. 	} else {
  79. 		playerct = --argc;
  80. 		players = (const char **)++argv;
  81. 	}
  82. 	raw_print("");
  83.  
  84. 	t1 = tt_head = newttentry();
  85. 	for (rank = 1; ; rank++) {
  86. 	    readentry(rfile, t1);
  87. 	    if (t1->points == 0) break;
  88. 	    if (!match_found &&
  89. 		    score_wanted(current_ver, rank, t1, playerct, players, uid))
  90. 		match_found = TRUE;
  91. 	    t1->tt_next = newttentry();
  92. 	    t1 = t1->tt_next;
  93. 	}
  94.  
  95. 	(void) fclose(rfile);
  96. 	if (init_done) {
  97. 	    free_dungeons();
  98. 	    dlb_cleanup();
  99. 	}
  100.  
  101. 	if (match_found) {
  102. 	    outheader();
  103. 	    t1 = tt_head;
  104. 	    for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
  105. 		if (score_wanted(current_ver, rank, t1, playerct, players, uid))
  106. 		    (void) outentry(rank, t1, 0);
  107. 	    }
  108. 	} else {
  109. 	    Sprintf(pbuf, "Cannot find any %sentries for ",
  110. 				current_ver ? "current " : "");
  111. 	    if (playerct < 1) Strcat(pbuf, "you.");
  112. 	    else {
  113. 		if (playerct > 1) Strcat(pbuf, "any of ");
  114. 		for (i = 0; i < playerct; i++) {
  115. 		    /* stop printing players if there are too many to fit */
  116. 		    if (strlen(pbuf) + strlen(players[i]) + 2 >= BUFSZ) {
  117. 			if (strlen(pbuf) < BUFSZ-4) Strcat(pbuf, "...");
  118. 			else Strcpy(pbuf+strlen(pbuf)-4, "...");
  119. 			break;
  120. 		    }
  121. 		    Strcat(pbuf, players[i]);
  122. 		    if (i < playerct-1) {
  123. 			if (players[i][0] == '-' &&
  124. 			    index("pr", players[i][1]) && players[i][2] == 0)
  125. 			    Strcat(pbuf, " ");
  126. 			else Strcat(pbuf, ":");
  127. 		    }
  128. 		}
  129. 	    }
  130. 	    raw_print(pbuf);
  131. 	    raw_printf("Usage: %s -s [-v] <playertypes> [maxrank] [playernames]",
  132.  
  133. 			 hname);
  134. 	    raw_printf("Player types are: [-p role] [-r race]");
  135. 	}
  136. 	free_ttlist(tt_head);
  137. #ifdef	AMIGA
  138. 	{
  139. 	    extern winid amii_rawprwin;
  140. 	    display_nhwindow(amii_rawprwin, 1);
  141. 	    destroy_nhwindow(amii_rawprwin);
  142. 	    amii_rawprwin = WIN_ERR;
  143. 	}
  144. #endif
  145. }

classmon[edit]

  1. STATIC_OVL int
  2. classmon(plch, fem)
  3. 	char *plch;
  4. 	boolean fem;
  5. {
  6. 	int i;
  7.  
  8. 	/* Look for this role in the role table */
  9. 	for (i = 0; roles[i].name.m; i++)
  10. 	    if (!strncmp(plch, roles[i].filecode, ROLESZ)) {
  11. 		if (fem && roles[i].femalenum != NON_PM)
  12. 		    return roles[i].femalenum;
  13. 		else if (roles[i].malenum != NON_PM)
  14. 		    return roles[i].malenum;
  15. 		else
  16. 		    return PM_HUMAN;
  17. 	    }
  18. 	/* this might be from a 3.2.x score for former Elf class */
  19. 	if (!strcmp(plch, "E")) return PM_RANGER;
  20.  
  21. 	impossible("What weird role is this? (%s)", plch);
  22. 	return (PM_HUMAN_MUMMY);
  23. }

tt_oname[edit]

  1. /*
  2. * Get a random player name and class from the high score list,
  3. * and attach them to an object (for statues or morgue corpses).
  4. */
  5. struct obj *
  6. tt_oname(otmp)
  7. struct obj *otmp;
  8. {
  9. 	int rank;
  10. 	register int i;
  11. 	register struct toptenentry *tt;
  12. 	FILE *rfile;
  13. 	struct toptenentry tt_buf;
  14.  
  15. 	if (!otmp) return((struct obj *) 0);
  16.  
  17. 	rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
  18. 	if (!rfile) {
  19. 		impossible("Cannot open record file!");
  20. 		return (struct obj *)0;
  21. 	}
  22.  
  23. 	tt = &tt_buf;
  24. 	rank = rnd(10);
  25. pickentry:
  26. 	for(i = rank; i; i--) {
  27. 	    readentry(rfile, tt);
  28. 	    if(tt->points == 0) break;
  29. 	}
  30.  
  31. 	if(tt->points == 0) {
  32. 		if(rank > 1) {
  33. 			rank = 1;
  34. 			rewind(rfile);
  35. 			goto pickentry;
  36. 		}
  37. 		otmp = (struct obj *) 0;
  38. 	} else {
  39. 		/* reset timer in case corpse started out as lizard or troll */
  40. 		if (otmp->otyp == CORPSE) obj_stop_timers(otmp);
  41. 		otmp->corpsenm = classmon(tt->plrole, (tt->plgend[0] == 'F'));
  42. 		otmp->owt = weight(otmp);
  43. 		otmp = oname(otmp, tt->name);
  44. 		if (otmp->otyp == CORPSE) start_corpse_timeout(otmp);
  45. 	}
  46.  
  47. 	(void) fclose(rfile);
  48. 	return otmp;
  49. }

nsb_mung_line[edit]

  1. #ifdef NO_SCAN_BRACK
  2. /* Lattice scanf isn't up to reading the scorefile.  What */
  3. /* follows deals with that; I admit it's ugly. (KL) */
  4. /* Now generally available (KL) */
  5. STATIC_OVL void
  6. nsb_mung_line(p)
  7. 	char *p;
  8. {
  9. 	while ((p = index(p, ' ')) != 0) *p = '|';
  10. }

nsb_unmung_line[edit]

  1. STATIC_OVL void
  2. nsb_unmung_line(p)
  3. 	char *p;
  4. {
  5. 	while ((p = index(p, '|')) != 0) *p = ' ';
  6. }
  7. #endif /* NO_SCAN_BRACK */
  8.  
  9. /*topten.c*/