Source:NetHack 2.3e/topten.c

From NetHackWiki
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.  }