Source:Hack 1.0/hack.end.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to hack.end.c from the source code of Hack 1.0. To link to a particular line, write [[Hack 1.0/hack.end.c#line123]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

Screenshots and source code from Hack are used under the CWI license.

1.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2.    
3.    #include "hack.h"
4.    #include <stdio.h>
5.    #include <signal.h>
6.    #define	Sprintf	(void) sprintf
7.    extern char plname[], pl_character[];
8.    extern char *itoa(), *ordin(), *eos(), *getlogin();
9.    
10.   xchar maxdlevel = 1;
11.   
12.   done1()
13.   {
14.   	(void) signal(SIGINT,SIG_IGN);
15.   	pline("Really quit?");
16.   	if(readchar() != 'y') {
17.   		(void) signal(SIGINT,done1);
18.   		clrlin();
19.   		(void) fflush(stdout);
20.   		if(multi > 0) nomul(0);
21.   		return(0);
22.   	}
23.   	done("quit");
24.   	/* NOTREACHED */
25.   }
26.   
27.   int done_stopprint;
28.   
29.   done_intr(){
30.   	done_stopprint++;
31.   	(void) signal(SIGINT,SIG_IGN);
32.   }
33.   
34.   done_in_by(mtmp) register struct monst *mtmp; {
35.   static char buf[BUFSZ];
36.   	pline("You die ...");
37.   	if(mtmp->data->mlet == ' '){
38.   		Sprintf(buf, "the ghost of %s", (char *) mtmp->mextra);
39.   		killer = buf;
40.   	} else if(mtmp->mnamelth) {
41.   		Sprintf(buf, "%s called %s",
42.   			mtmp->data->mname, NAME(mtmp));
43.   		killer = buf;
44.   	} else if(mtmp->minvis) {
45.   		Sprintf(buf, "invisible %s", mtmp->data->mname);
46.   		killer = buf;
47.   	} else killer = mtmp->data->mname;
48.   	done("died");
49.   }
50.   
51.   /* called with arg "died", "escaped", "quit", "choked", "panic"
52.      or "starved" */
53.   /* Be careful not to call panic from here! */
54.   done(st1)
55.   register char *st1;
56.   {
57.   
58.   #ifdef WIZARD
59.   	if(wizard && *st1 == 'd'){
60.   		u.ustr = u.ustrmax += 2;
61.   		u.uhp = u.uhpmax += 10;
62.   		if(uarm) uarm->spe++;
63.   		if(uwep) uwep->spe++; /* NB: uwep need not be a weapon! */
64.   		u.uswldtim = 0;
65.   		pline("For some reason you are still alive.");
66.   		flags.move = 0;
67.   		if(multi > 0) multi = 0; else multi = -1;
68.   		flags.botl = 1;
69.   		return;
70.   	}
71.   #endif WIZARD
72.   	(void) signal(SIGINT, done_intr);
73.   	if(*st1 == 'q' && u.uhp < 1){
74.   		st1 = "died";
75.   		killer = "quit while already on Charon's boat";
76.   	}
77.   	if(*st1 == 's') killer = "starvation";
78.   	paybill();
79.   	clearlocks();
80.   	if(index("cds", *st1)){
81.   		savebones();
82.   		outrip();
83.   	}
84.   	settty((char *) 0);	/* does a cls() */
85.   	if(!done_stopprint)
86.   		printf("Goodbye %s %s...\n\n", pl_character, plname);
87.   	{ long int tmp;
88.   	tmp = u.ugold - u.ugold0;
89.   	if(tmp < 0) tmp = 0;
90.   	if(*st1 == 'd') tmp -= tmp/10;
91.   	else killer = st1;
92.   	u.urexp += tmp;
93.   	}
94.   	if(*st1 == 'e') {
95.   		extern struct monst *mydogs;
96.   		register struct monst *mtmp = mydogs;
97.   		register struct obj *otmp;
98.   		register int i;
99.   		register unsigned worthlessct = 0;
100.  
101.  		u.urexp += 50 * maxdlevel;
102.  		if(mtmp) {
103.  			if(!done_stopprint) printf("You");
104.  			while(mtmp) {
105.  				if(!done_stopprint)
106.  					printf(" and %s", monnam(mtmp));
107.  				u.urexp += mtmp->mhp;
108.  				mtmp = mtmp->nmon;
109.  			}
110.  			if(!done_stopprint)
111.  		    printf("\nescaped from the dungeon with %lu points,\n",
112.  			u.urexp);
113.  		} else
114.  		if(!done_stopprint)
115.  		  printf("You escaped from the dungeon with %lu points,\n",
116.  		    u.urexp);
117.  		for(otmp = invent; otmp; otmp = otmp->nobj) {
118.  			if(otmp->olet == GEM_SYM){
119.  				objects[otmp->otyp].oc_name_known = 1;
120.  				i = otmp->quan*objects[otmp->otyp].g_val;
121.  				if(i == 0) {
122.  					worthlessct += otmp->quan;
123.  					continue;
124.  				}
125.  				u.urexp += i;
126.  				if(!done_stopprint)
127.  				  printf("\t%s (worth %d Zorkmids),\n",
128.  				    doname(otmp), i);
129.  			} else if(otmp->olet == AMULET_SYM) {
130.  				otmp->known = 1;
131.  				i = (otmp->spe < 0) ? 2 : 5000;
132.  				u.urexp += i;
133.  				if(!done_stopprint)
134.  				  printf("\t%s (worth %d Zorkmids),\n",
135.  				    doname(otmp), i);
136.  				if(otmp->spe >= 0) u.urexp *= 2;
137.  			}
138.  		}
139.  		if(worthlessct) if(!done_stopprint)
140.  		  printf("\t%d worthless piece%s of coloured glass,\n",
141.  		  worthlessct, plur(worthlessct));
142.  		killer=st1;
143.  	} else
144.  		if(!done_stopprint)
145.  		  printf("You %s on dungeon level %d with %lu points,\n",
146.  		    st1,dlevel,u.urexp);
147.  	if(!done_stopprint)
148.  	  printf("and %lu piece%s of gold, after %lu move%s.\n",
149.  	    u.ugold, (u.ugold == 1) ? "" : "s",
150.  	    moves, (moves == 1) ? "" : "s");
151.  	if(!done_stopprint)
152.    printf("You were level %d with a maximum of %d hit points when you %s.\n",
153.  	    u.ulevel, u.uhpmax, st1);
154.  	if(*st1 == 'e'){
155.  		getret();	/* all those pieces of coloured glass ... */
156.  		cls();
157.  	}
158.  #ifdef WIZARD
159.  	if(!wizard)
160.  #endif WIZARD
161.  		topten();
162.  	if(done_stopprint) printf("\n\n");
163.  	exit(0);
164.  }
165.  
166.  #define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
167.  #define	NAMSZ	8
168.  #define	DTHSZ	40
169.  #define	PERSMAX	1
170.  #define	POINTSMIN	1	/* must be > 0 */
171.  #define	ENTRYMAX	100	/* must be >= 10 */
172.  struct toptenentry {
173.  	struct toptenentry *tt_next;
174.  	long int points;
175.  	int level,maxlvl,hp,maxhp;
176.  	char plchar;
177.  	char str[NAMSZ+1];
178.  	char death[DTHSZ+1];
179.  } *tt_head;
180.  
181.  topten(){
182.  	int rank, rank0 = -1, rank1 = 0;
183.  	int occ_cnt = PERSMAX;
184.  	register struct toptenentry *t0, *t1, *tprev;
185.  	char *recfile = "record";
186.  	FILE *rfile;
187.  	register flg = 0;
188.  
189.  	if(!(rfile = fopen(recfile,"r"))){
190.  		puts("Cannot open record file!");
191.  		return;
192.  	}
193.  	(void) putchar('\n');
194.  
195.  	/* create a new 'topten' entry */
196.  	t0 = newttentry();
197.  	t0->level = dlevel;
198.  	t0->maxlvl = maxdlevel;
199.  	t0->hp = u.uhp;
200.  	t0->maxhp = u.uhpmax;
201.  	t0->points = u.urexp;
202.  	t0->plchar = pl_character[0];
203.  	(void) strncpy(t0->str, plname, NAMSZ);
204.  	(t0->str)[NAMSZ] = 0;
205.  	(void) strncpy(t0->death, killer, DTHSZ);
206.  	(t0->death)[DTHSZ] = 0;
207.  
208.  	/* assure minimum number of points */
209.  	if(t0->points < POINTSMIN)
210.  		t0->points = 0;
211.  
212.  	t1 = tt_head = newttentry();
213.  	tprev = 0;
214.  	/* rank0: -1 undefined, 0 not_on_list, n n_th on list */
215.  	for(rank = 1; ; ) {
216.  	  if(fscanf(rfile, "%d %d %d %d %ld %c %[^,],%[^\n]",
217.  		&t1->level, &t1->maxlvl,
218.  		&t1->hp, &t1->maxhp, &t1->points,
219.  		&t1->plchar, t1->str, t1->death) != 8
220.  	  || t1->points < POINTSMIN)
221.  			t1->points = 0;
222.  	  if(rank0 < 0 && t1->points < t0->points) {
223.  		rank0 = rank++;
224.  		if(tprev == 0)
225.  			tt_head = t0;
226.  		else
227.  			tprev->tt_next = t0;
228.  		t0->tt_next = t1;
229.  		occ_cnt--;
230.  		flg++;		/* ask for a rewrite */
231.  	  } else
232.  		tprev = t1;
233.  	  if(t1->points == 0) break;
234.  	  if(strncmp(t1->str, t0->str, NAMSZ) == 0 &&
235.  	     t1->plchar == t0->plchar && --occ_cnt <= 0){
236.  		if(rank0 < 0){
237.  			rank0 = 0;
238.  			rank1 = rank;
239.  	printf("You didn't beat your previous score of %ld points.\n\n",
240.  				t1->points);
241.  		}
242.  		if(occ_cnt < 0){
243.  			flg++;
244.  			continue;
245.  		}
246.  	  }
247.  	  if(rank <= ENTRYMAX){
248.  	  	t1 = t1->tt_next = newttentry();
249.  	  	rank++;
250.  	  }
251.  	  if(rank > ENTRYMAX){
252.  		t1->points = 0;
253.  		break;
254.  	  }
255.  	}
256.  	if(flg) {	/* rewrite record file */
257.  		(void) fclose(rfile);
258.  		if(!(rfile=fopen(recfile,"w"))){
259.  			puts("Cannot write record file\n");
260.  			return;
261.  		}
262.  
263.  		if(!done_stopprint) if(rank0 > 0){
264.  		    if(rank0 <= 10)
265.  			puts("You made the top ten list!\n");
266.  		    else
267.  		printf("You reached the %d%s place on the top %d list.\n\n",
268.  			rank0, ordin(rank0), ENTRYMAX);
269.  		}
270.  	}
271.  	if(rank0 == 0) rank0 = rank1;
272.  	if(rank0 <= 0) rank0 = rank;
273.  	if(!done_stopprint) outheader();
274.  	t1 = tt_head;
275.  	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
276.  	  if(flg) fprintf(rfile,"%d %d %d %d %ld %c %s,%s\n",
277.  	    t1->level, t1->maxlvl,
278.  	    t1->hp, t1->maxhp, t1->points,
279.  	    t1->plchar,t1->str,t1->death);
280.  	  if(done_stopprint) continue;
281.  	  if(rank > 5 && (rank < rank0 - 4 || rank > rank0 + 4))
282.  	      continue;
283.  	  if(rank == rank0 - 4 && rank0 > 10) (void) putchar('\n');
284.  	  if(rank != rank0)
285.  		(void) outentry(rank, t1, 0);
286.  	  else if(!rank1)
287.  		(void) outentry(rank, t1, 1);
288.  	  else {
289.  		int t0lth = outentry(0, t0, -1);
290.  		int t1lth = outentry(rank, t1, t0lth);
291.  		if(t1lth > t0lth) t0lth = t1lth;
292.  		(void) outentry(0, t0, t0lth);
293.  	  }
294.  	}
295.  	if(rank0 >= rank)
296.  		(void) outentry(0, t0, 1);
297.  	(void) fclose(rfile);
298.  }
299.  
300.  outheader() {
301.  char linebuf[BUFSZ];
302.  register char *bp;
303.  	(void) strcpy(linebuf, "Number Points  Name");
304.  	bp = eos(linebuf);
305.  	while(bp < linebuf + COLNO - 9) *bp++ = ' ';
306.  	(void) strcpy(bp, "Hp [max]");
307.  	puts(linebuf);
308.  }
309.  
310.  /* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */
311.  int
312.  outentry(rank,t1,so) register struct toptenentry *t1; {
313.  boolean quit = FALSE, killed = FALSE, starv = FALSE;
314.  char linebuf[BUFSZ];
315.  	linebuf[0] = 0;
316.  	if(rank) Sprintf(eos(linebuf), "%3d", rank);
317.  		else Sprintf(eos(linebuf), "   ");
318.  	Sprintf(eos(linebuf), " %6ld %8s", t1->points, t1->str);
319.  	if(t1->plchar == 'X') Sprintf(eos(linebuf), " ");
320.  	else Sprintf(eos(linebuf), "-%c ", t1->plchar);
321.  	if(!strcmp("escaped", t1->death))
322.  	  Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",
323.  	    t1->maxlvl);
324.  	else {
325.  	  if(!strncmp(t1->death,"quit",4))
326.  	    Sprintf(eos(linebuf), "quit"), quit = TRUE;
327.  	  else if(!strcmp(t1->death,"choked"))
328.  	    Sprintf(eos(linebuf), "choked in his food");
329.  	  else if(!strncmp(t1->death,"starv",5))
330.  	    Sprintf(eos(linebuf), "starved to death"), starv = TRUE;
331.  	  else Sprintf(eos(linebuf), "was killed"), killed = TRUE;
332.  	  Sprintf(eos(linebuf), " on%s level %d",
333.  	    (killed || starv) ? "" : " dungeon", t1->level);
334.  	  if(t1->maxlvl != t1->level)
335.  	    Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
336.  	  if(quit && t1->death[4]) Sprintf(eos(linebuf), t1->death + 4);
337.  	}
338.  	if(killed) Sprintf(eos(linebuf), " by %s%s",
339.  	  !strncmp(t1->death, "the ", 4) ? "" :
340.  	  index(vowels,*t1->death) ? "an " : "a ",
341.  	  t1->death);
342.  	Sprintf(eos(linebuf), ".");
343.  	if(t1->maxhp) {
344.  	  register char *bp = eos(linebuf);
345.  	  char hpbuf[10];
346.  	  int hppos;
347.  	  Sprintf(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-");
348.  	  hppos = COLNO - 7 - strlen(hpbuf);
349.  	  if(bp <= linebuf + hppos) {
350.  	    while(bp < linebuf + hppos) *bp++ = ' ';
351.  	    (void) strcpy(bp, hpbuf);
352.  	    Sprintf(eos(bp), " [%d]", t1->maxhp);
353.  	  }
354.  	}
355.  	if(so == 0) puts(linebuf);
356.  	else if(so > 0) {
357.  	  register char *bp = eos(linebuf);
358.  	  if(so >= COLNO) so = COLNO-1;
359.  	  while(bp < linebuf + so) *bp++ = ' ';
360.  	  *bp = 0;
361.  	  standoutbeg();
362.  	  fputs(linebuf,stdout);
363.  	  standoutend();
364.  	  (void) putchar('\n');
365.  	}
366.  	return(strlen(linebuf));
367.  }
368.  
369.  char *
370.  itoa(a) int a; {
371.  static char buf[12];
372.  	Sprintf(buf,"%d",a);
373.  	return(buf);
374.  }
375.  
376.  char *
377.  ordin(n) int n; {
378.  register int d = n%10;
379.  	return((d==0 || d>3 || n/10==1) ? "th" : (d==1) ? "st" :
380.  		(d==2) ? "nd" : "rd");
381.  }
382.  
383.  clearlocks(){
384.  register x;
385.  	(void) signal(SIGHUP,SIG_IGN);
386.  	for(x = 1; x <= maxdlevel; x++) {
387.  		glo(x);
388.  		(void) unlink(lock);	/* not all levels need be present */
389.  	}
390.  	(*index(lock,'.')) = 0;
391.  	(void) unlink(lock);
392.  }
393.  
394.  #ifdef NOSAVEONHANGUP
395.  hangup(){
396.  	(void) signal(SIGINT,SIG_IGN);
397.  	clearlocks();
398.  	exit(1);
399.  }
400.  #endif NOSAVEONHANGUP
401.  
402.  char *
403.  eos(s) register char *s; {
404.  	while(*s) s++;
405.  	return(s);
406.  }
407.  
408.  /* it is the callers responsibility to check that there is room for c */
409.  charcat(s,c) register char *s, c; {
410.  	while(*s) s++;
411.  	*s++ = c;
412.  	*s = 0;
413.  }
414.  
415.  prscore(argc,argv) int argc; char **argv; {
416.  	extern char *hname;
417.  	char *player0;
418.  	char **players;
419.  	int playerct;
420.  	int rank;
421.  	register struct toptenentry *t1;
422.  	char *recfile = "record";
423.  	FILE *rfile;
424.  	register flg = 0;
425.  	register int i;
426.  
427.  	if(!(rfile = fopen(recfile,"r"))){
428.  		puts("Cannot open record file!");
429.  		return;
430.  	}
431.  
432.  	if(argc > 1 && !strncmp(argv[1], "-s", 2)){
433.  		if(!argv[1][2]){
434.  			argc--;
435.  			argv++;
436.  		} else if(!argv[1][3] && index("CFKSTWX", argv[1][2])) {
437.  			argv[1]++;
438.  			argv[1][0] = '-';
439.  		} else	argv[1] += 2;
440.  	}
441.  	if(argc <= 1){
442.  		player0 = getlogin();
443.  		if(!player0) player0 = "player";
444.  		playerct = 1;
445.  		players = &player0;
446.  	} else {
447.  		playerct = --argc;
448.  		players = ++argv;
449.  	}
450.  	putchar('\n');
451.  
452.  	t1 = tt_head = newttentry();
453.  	for(rank = 1; ; rank++) {
454.  	  if(fscanf(rfile, "%d %d %d %d %ld %c %[^,],%[^\n]",
455.  		&t1->level, &t1->maxlvl,
456.  		&t1->hp, &t1->maxhp, &t1->points,
457.  		&t1->plchar, t1->str, t1->death) != 8)
458.  			t1->points = 0;
459.  	  if(t1->points == 0) break;
460.  	  for(i = 0; i < playerct; i++){
461.  		if(strcmp(players[i], "all") == 0 ||
462.  		   strncmp(t1->str, players[i], NAMSZ) == 0 ||
463.  		  (players[i][0] == '-' &&
464.  		   players[i][1] == t1->plchar &&
465.  		   players[i][2] == 0) ||
466.  		  (digit(players[i][0]) && rank <= atoi(players[i])))
467.  			flg++;
468.  	  }
469.  	  t1 = t1->tt_next = newttentry();
470.  	}
471.  	(void) fclose(rfile);
472.  	if(!flg) {
473.  		printf("Cannot find any entries for ");
474.  		if(playerct > 1) printf("any of ");
475.  		for(i=0; i<playerct; i++)
476.  			printf("%s%s", players[i], (i<playerct-1)?", ":".\n");
477.  		printf("Call is: %s -s [playernames]\n", hname);
478.  		return;
479.  	}
480.  
481.  	outheader();
482.  	t1 = tt_head;
483.  	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
484.  		for(i = 0; i < playerct; i++){
485.  			if(strcmp(players[i], "all") == 0 ||
486.  			   strncmp(t1->str, players[i], NAMSZ) == 0 ||
487.  			  (players[i][0] == '-' &&
488.  			   players[i][1] == t1->plchar &&
489.  			   players[i][2] == 0) ||
490.  			  (digit(players[i][0]) && rank <= atoi(players[i])))
491.  				goto out;
492.  		}
493.  		continue;
494.  	out:
495.  	  (void) outentry(rank, t1, 0);
496.  	}
497.  }