Home | History | Annotate | Line # | Download | only in hack
hack.end.c revision 1.2
      1  1.2  mycroft /*
      2  1.2  mycroft  * Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985.
      3  1.2  mycroft  */
      4  1.2  mycroft 
      5  1.2  mycroft #ifndef lint
      6  1.2  mycroft static char rcsid[] = "$Id: hack.end.c,v 1.2 1993/08/02 17:17:10 mycroft Exp $";
      7  1.2  mycroft #endif /* not lint */
      8  1.1      cgd 
      9  1.1      cgd #include "hack.h"
     10  1.1      cgd #include <stdio.h>
     11  1.1      cgd #include <signal.h>
     12  1.1      cgd #define	Sprintf	(void) sprintf
     13  1.1      cgd extern char plname[], pl_character[];
     14  1.1      cgd extern char *itoa(), *ordin(), *eos();
     15  1.1      cgd 
     16  1.1      cgd xchar maxdlevel = 1;
     17  1.1      cgd 
     18  1.1      cgd void
     19  1.1      cgd done1()
     20  1.1      cgd {
     21  1.1      cgd 	(void) signal(SIGINT,SIG_IGN);
     22  1.1      cgd 	pline("Really quit?");
     23  1.1      cgd 	if(readchar() != 'y') {
     24  1.1      cgd 		(void) signal(SIGINT,done1);
     25  1.1      cgd 		clrlin();
     26  1.1      cgd 		(void) fflush(stdout);
     27  1.1      cgd 		if(multi > 0) nomul(0);
     28  1.1      cgd 		return;
     29  1.1      cgd 	}
     30  1.1      cgd 	done("quit");
     31  1.1      cgd 	/* NOTREACHED */
     32  1.1      cgd }
     33  1.1      cgd 
     34  1.1      cgd int done_stopprint;
     35  1.1      cgd int done_hup;
     36  1.1      cgd 
     37  1.1      cgd void
     38  1.1      cgd done_intr(){
     39  1.1      cgd 	done_stopprint++;
     40  1.1      cgd 	(void) signal(SIGINT, SIG_IGN);
     41  1.1      cgd 	(void) signal(SIGQUIT, SIG_IGN);
     42  1.1      cgd }
     43  1.1      cgd 
     44  1.1      cgd void
     45  1.1      cgd done_hangup(){
     46  1.1      cgd 	done_hup++;
     47  1.1      cgd 	(void) signal(SIGHUP, SIG_IGN);
     48  1.1      cgd 	done_intr();
     49  1.1      cgd }
     50  1.1      cgd 
     51  1.1      cgd done_in_by(mtmp) register struct monst *mtmp; {
     52  1.1      cgd static char buf[BUFSZ];
     53  1.1      cgd 	pline("You die ...");
     54  1.1      cgd 	if(mtmp->data->mlet == ' '){
     55  1.1      cgd 		Sprintf(buf, "the ghost of %s", (char *) mtmp->mextra);
     56  1.1      cgd 		killer = buf;
     57  1.1      cgd 	} else if(mtmp->mnamelth) {
     58  1.1      cgd 		Sprintf(buf, "%s called %s",
     59  1.1      cgd 			mtmp->data->mname, NAME(mtmp));
     60  1.1      cgd 		killer = buf;
     61  1.1      cgd 	} else if(mtmp->minvis) {
     62  1.1      cgd 		Sprintf(buf, "invisible %s", mtmp->data->mname);
     63  1.1      cgd 		killer = buf;
     64  1.1      cgd 	} else killer = mtmp->data->mname;
     65  1.1      cgd 	done("died");
     66  1.1      cgd }
     67  1.1      cgd 
     68  1.1      cgd /* called with arg "died", "drowned", "escaped", "quit", "choked", "panicked",
     69  1.1      cgd    "burned", "starved" or "tricked" */
     70  1.1      cgd /* Be careful not to call panic from here! */
     71  1.1      cgd done(st1)
     72  1.1      cgd register char *st1;
     73  1.1      cgd {
     74  1.1      cgd 
     75  1.1      cgd #ifdef WIZARD
     76  1.1      cgd 	if(wizard && *st1 == 'd'){
     77  1.1      cgd 		u.uswldtim = 0;
     78  1.1      cgd 		if(u.uhpmax < 0) u.uhpmax = 100;	/* arbitrary */
     79  1.1      cgd 		u.uhp = u.uhpmax;
     80  1.1      cgd 		pline("For some reason you are still alive.");
     81  1.1      cgd 		flags.move = 0;
     82  1.1      cgd 		if(multi > 0) multi = 0; else multi = -1;
     83  1.1      cgd 		flags.botl = 1;
     84  1.1      cgd 		return;
     85  1.1      cgd 	}
     86  1.1      cgd #endif WIZARD
     87  1.1      cgd 	(void) signal(SIGINT, done_intr);
     88  1.1      cgd 	(void) signal(SIGQUIT, done_intr);
     89  1.1      cgd 	(void) signal(SIGHUP, done_hangup);
     90  1.1      cgd 	if(*st1 == 'q' && u.uhp < 1){
     91  1.1      cgd 		st1 = "died";
     92  1.1      cgd 		killer = "quit while already on Charon's boat";
     93  1.1      cgd 	}
     94  1.1      cgd 	if(*st1 == 's') killer = "starvation"; else
     95  1.1      cgd 	if(*st1 == 'd' && st1[1] == 'r') killer = "drowning"; else
     96  1.1      cgd 	if(*st1 == 'p') killer = "panic"; else
     97  1.1      cgd 	if(*st1 == 't') killer = "trickery"; else
     98  1.1      cgd 	if(!index("bcd", *st1)) killer = st1;
     99  1.1      cgd 	paybill();
    100  1.1      cgd 	clearlocks();
    101  1.1      cgd 	if(flags.toplin == 1) more();
    102  1.1      cgd 	if(index("bcds", *st1)){
    103  1.1      cgd #ifdef WIZARD
    104  1.1      cgd 	    if(!wizard)
    105  1.1      cgd #endif WIZARD
    106  1.1      cgd 		savebones();
    107  1.1      cgd 		if(!flags.notombstone)
    108  1.1      cgd 			outrip();
    109  1.1      cgd 	}
    110  1.1      cgd 	if(*st1 == 'c') killer = st1;		/* after outrip() */
    111  1.1      cgd 	settty((char *) 0);	/* does a clear_screen() */
    112  1.1      cgd 	if(!done_stopprint)
    113  1.1      cgd 		printf("Goodbye %s %s...\n\n", pl_character, plname);
    114  1.1      cgd 	{ long int tmp;
    115  1.1      cgd 	  tmp = u.ugold - u.ugold0;
    116  1.1      cgd 	  if(tmp < 0)
    117  1.1      cgd 		tmp = 0;
    118  1.1      cgd 	  if(*st1 == 'd' || *st1 == 'b')
    119  1.1      cgd 		tmp -= tmp/10;
    120  1.1      cgd 	  u.urexp += tmp;
    121  1.1      cgd 	  u.urexp += 50 * maxdlevel;
    122  1.1      cgd 	  if(maxdlevel > 20)
    123  1.1      cgd 		u.urexp += 1000*((maxdlevel > 30) ? 10 : maxdlevel - 20);
    124  1.1      cgd 	}
    125  1.1      cgd 	if(*st1 == 'e') {
    126  1.1      cgd 		extern struct monst *mydogs;
    127  1.1      cgd 		register struct monst *mtmp;
    128  1.1      cgd 		register struct obj *otmp;
    129  1.1      cgd 		register int i;
    130  1.1      cgd 		register unsigned worthlessct = 0;
    131  1.1      cgd 		boolean has_amulet = FALSE;
    132  1.1      cgd 
    133  1.1      cgd 		killer = st1;
    134  1.1      cgd 		keepdogs();
    135  1.1      cgd 		mtmp = mydogs;
    136  1.1      cgd 		if(mtmp) {
    137  1.1      cgd 			if(!done_stopprint) printf("You");
    138  1.1      cgd 			while(mtmp) {
    139  1.1      cgd 				if(!done_stopprint)
    140  1.1      cgd 					printf(" and %s", monnam(mtmp));
    141  1.1      cgd 				if(mtmp->mtame)
    142  1.1      cgd 					u.urexp += mtmp->mhp;
    143  1.1      cgd 				mtmp = mtmp->nmon;
    144  1.1      cgd 			}
    145  1.1      cgd 			if(!done_stopprint)
    146  1.1      cgd 		    printf("\nescaped from the dungeon with %ld points,\n",
    147  1.1      cgd 			u.urexp);
    148  1.1      cgd 		} else
    149  1.1      cgd 		if(!done_stopprint)
    150  1.1      cgd 		  printf("You escaped from the dungeon with %ld points,\n",
    151  1.1      cgd 		    u.urexp);
    152  1.1      cgd 		for(otmp = invent; otmp; otmp = otmp->nobj) {
    153  1.1      cgd 			if(otmp->olet == GEM_SYM){
    154  1.1      cgd 				objects[otmp->otyp].oc_name_known = 1;
    155  1.1      cgd 				i = otmp->quan*objects[otmp->otyp].g_val;
    156  1.1      cgd 				if(i == 0) {
    157  1.1      cgd 					worthlessct += otmp->quan;
    158  1.1      cgd 					continue;
    159  1.1      cgd 				}
    160  1.1      cgd 				u.urexp += i;
    161  1.1      cgd 				if(!done_stopprint)
    162  1.1      cgd 				  printf("\t%s (worth %d Zorkmids),\n",
    163  1.1      cgd 				    doname(otmp), i);
    164  1.1      cgd 			} else if(otmp->olet == AMULET_SYM) {
    165  1.1      cgd 				otmp->known = 1;
    166  1.1      cgd 				i = (otmp->spe < 0) ? 2 : 5000;
    167  1.1      cgd 				u.urexp += i;
    168  1.1      cgd 				if(!done_stopprint)
    169  1.1      cgd 				  printf("\t%s (worth %d Zorkmids),\n",
    170  1.1      cgd 				    doname(otmp), i);
    171  1.1      cgd 				if(otmp->spe >= 0) {
    172  1.1      cgd 					has_amulet = TRUE;
    173  1.1      cgd 					killer = "escaped (with amulet)";
    174  1.1      cgd 				}
    175  1.1      cgd 			}
    176  1.1      cgd 		}
    177  1.1      cgd 		if(worthlessct) if(!done_stopprint)
    178  1.1      cgd 		  printf("\t%u worthless piece%s of coloured glass,\n",
    179  1.1      cgd 		  worthlessct, plur(worthlessct));
    180  1.1      cgd 		if(has_amulet) u.urexp *= 2;
    181  1.1      cgd 	} else
    182  1.1      cgd 		if(!done_stopprint)
    183  1.1      cgd 		  printf("You %s on dungeon level %d with %ld points,\n",
    184  1.1      cgd 		    st1, dlevel, u.urexp);
    185  1.1      cgd 	if(!done_stopprint)
    186  1.1      cgd 	  printf("and %ld piece%s of gold, after %ld move%s.\n",
    187  1.1      cgd 	    u.ugold, plur(u.ugold), moves, plur(moves));
    188  1.1      cgd 	if(!done_stopprint)
    189  1.1      cgd   printf("You were level %u with a maximum of %d hit points when you %s.\n",
    190  1.1      cgd 	    u.ulevel, u.uhpmax, st1);
    191  1.1      cgd 	if(*st1 == 'e' && !done_stopprint){
    192  1.1      cgd 		getret();	/* all those pieces of coloured glass ... */
    193  1.1      cgd 		cls();
    194  1.1      cgd 	}
    195  1.1      cgd #ifdef WIZARD
    196  1.1      cgd 	if(!wizard)
    197  1.1      cgd #endif WIZARD
    198  1.1      cgd 		topten();
    199  1.1      cgd 	if(done_stopprint) printf("\n\n");
    200  1.1      cgd 	exit(0);
    201  1.1      cgd }
    202  1.1      cgd 
    203  1.1      cgd #define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
    204  1.1      cgd #define	NAMSZ	8
    205  1.1      cgd #define	DTHSZ	40
    206  1.1      cgd #define	PERSMAX	1
    207  1.1      cgd #define	POINTSMIN	1	/* must be > 0 */
    208  1.1      cgd #define	ENTRYMAX	100	/* must be >= 10 */
    209  1.1      cgd #define	PERS_IS_UID		/* delete for PERSMAX per name; now per uid */
    210  1.1      cgd struct toptenentry {
    211  1.1      cgd 	struct toptenentry *tt_next;
    212  1.1      cgd 	long int points;
    213  1.1      cgd 	int level,maxlvl,hp,maxhp;
    214  1.1      cgd 	int uid;
    215  1.1      cgd 	char plchar;
    216  1.1      cgd 	char sex;
    217  1.1      cgd 	char name[NAMSZ+1];
    218  1.1      cgd 	char death[DTHSZ+1];
    219  1.1      cgd 	char date[7];		/* yymmdd */
    220  1.1      cgd } *tt_head;
    221  1.1      cgd 
    222  1.1      cgd topten(){
    223  1.1      cgd 	int uid = getuid();
    224  1.1      cgd 	int rank, rank0 = -1, rank1 = 0;
    225  1.1      cgd 	int occ_cnt = PERSMAX;
    226  1.1      cgd 	register struct toptenentry *t0, *t1, *tprev;
    227  1.1      cgd 	char *recfile = RECORD;
    228  1.1      cgd 	char *reclock = "record_lock";
    229  1.1      cgd 	int sleepct = 300;
    230  1.1      cgd 	FILE *rfile;
    231  1.1      cgd 	register flg = 0;
    232  1.1      cgd 	extern char *getdate();
    233  1.1      cgd #define	HUP	if(!done_hup)
    234  1.1      cgd 	while(link(recfile, reclock) == -1) {
    235  1.1      cgd 		HUP perror(reclock);
    236  1.1      cgd 		if(!sleepct--) {
    237  1.1      cgd 			HUP puts("I give up. Sorry.");
    238  1.1      cgd 			HUP puts("Perhaps there is an old record_lock around?");
    239  1.1      cgd 			return;
    240  1.1      cgd 		}
    241  1.1      cgd 		HUP printf("Waiting for access to record file. (%d)\n",
    242  1.1      cgd 			sleepct);
    243  1.1      cgd 		HUP (void) fflush(stdout);
    244  1.1      cgd 		sleep(1);
    245  1.1      cgd 	}
    246  1.1      cgd 	if(!(rfile = fopen(recfile,"r"))){
    247  1.1      cgd 		HUP puts("Cannot open record file!");
    248  1.1      cgd 		goto unlock;
    249  1.1      cgd 	}
    250  1.1      cgd 	HUP (void) putchar('\n');
    251  1.1      cgd 
    252  1.1      cgd 	/* create a new 'topten' entry */
    253  1.1      cgd 	t0 = newttentry();
    254  1.1      cgd 	t0->level = dlevel;
    255  1.1      cgd 	t0->maxlvl = maxdlevel;
    256  1.1      cgd 	t0->hp = u.uhp;
    257  1.1      cgd 	t0->maxhp = u.uhpmax;
    258  1.1      cgd 	t0->points = u.urexp;
    259  1.1      cgd 	t0->plchar = pl_character[0];
    260  1.1      cgd 	t0->sex = (flags.female ? 'F' : 'M');
    261  1.1      cgd 	t0->uid = uid;
    262  1.1      cgd 	(void) strncpy(t0->name, plname, NAMSZ);
    263  1.1      cgd 	(t0->name)[NAMSZ] = 0;
    264  1.1      cgd 	(void) strncpy(t0->death, killer, DTHSZ);
    265  1.1      cgd 	(t0->death)[DTHSZ] = 0;
    266  1.1      cgd 	(void) strcpy(t0->date, getdate());
    267  1.1      cgd 
    268  1.1      cgd 	/* assure minimum number of points */
    269  1.1      cgd 	if(t0->points < POINTSMIN)
    270  1.1      cgd 		t0->points = 0;
    271  1.1      cgd 
    272  1.1      cgd 	t1 = tt_head = newttentry();
    273  1.1      cgd 	tprev = 0;
    274  1.1      cgd 	/* rank0: -1 undefined, 0 not_on_list, n n_th on list */
    275  1.1      cgd 	for(rank = 1; ; ) {
    276  1.1      cgd 	  if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
    277  1.1      cgd 		t1->date, &t1->uid,
    278  1.1      cgd 		&t1->level, &t1->maxlvl,
    279  1.1      cgd 		&t1->hp, &t1->maxhp, &t1->points,
    280  1.1      cgd 		&t1->plchar, &t1->sex, t1->name, t1->death) != 11
    281  1.1      cgd 	  || t1->points < POINTSMIN)
    282  1.1      cgd 			t1->points = 0;
    283  1.1      cgd 	  if(rank0 < 0 && t1->points < t0->points) {
    284  1.1      cgd 		rank0 = rank++;
    285  1.1      cgd 		if(tprev == 0)
    286  1.1      cgd 			tt_head = t0;
    287  1.1      cgd 		else
    288  1.1      cgd 			tprev->tt_next = t0;
    289  1.1      cgd 		t0->tt_next = t1;
    290  1.1      cgd 		occ_cnt--;
    291  1.1      cgd 		flg++;		/* ask for a rewrite */
    292  1.1      cgd 	  } else
    293  1.1      cgd 		tprev = t1;
    294  1.1      cgd 	  if(t1->points == 0) break;
    295  1.1      cgd 	  if(
    296  1.1      cgd #ifdef PERS_IS_UID
    297  1.1      cgd 	     t1->uid == t0->uid &&
    298  1.1      cgd #else
    299  1.1      cgd 	     strncmp(t1->name, t0->name, NAMSZ) == 0 &&
    300  1.1      cgd #endif PERS_IS_UID
    301  1.1      cgd 	     t1->plchar == t0->plchar && --occ_cnt <= 0){
    302  1.1      cgd 		if(rank0 < 0){
    303  1.1      cgd 			rank0 = 0;
    304  1.1      cgd 			rank1 = rank;
    305  1.1      cgd 	HUP printf("You didn't beat your previous score of %ld points.\n\n",
    306  1.1      cgd 				t1->points);
    307  1.1      cgd 		}
    308  1.1      cgd 		if(occ_cnt < 0){
    309  1.1      cgd 			flg++;
    310  1.1      cgd 			continue;
    311  1.1      cgd 		}
    312  1.1      cgd 	  }
    313  1.1      cgd 	  if(rank <= ENTRYMAX){
    314  1.1      cgd 	  	t1 = t1->tt_next = newttentry();
    315  1.1      cgd 	  	rank++;
    316  1.1      cgd 	  }
    317  1.1      cgd 	  if(rank > ENTRYMAX){
    318  1.1      cgd 		t1->points = 0;
    319  1.1      cgd 		break;
    320  1.1      cgd 	  }
    321  1.1      cgd 	}
    322  1.1      cgd 	if(flg) {	/* rewrite record file */
    323  1.1      cgd 		(void) fclose(rfile);
    324  1.1      cgd 		if(!(rfile = fopen(recfile,"w"))){
    325  1.1      cgd 			HUP puts("Cannot write record file\n");
    326  1.1      cgd 			goto unlock;
    327  1.1      cgd 		}
    328  1.1      cgd 
    329  1.1      cgd 		if(!done_stopprint) if(rank0 > 0){
    330  1.1      cgd 		    if(rank0 <= 10)
    331  1.1      cgd 			puts("You made the top ten list!\n");
    332  1.1      cgd 		    else
    333  1.1      cgd 		printf("You reached the %d%s place on the top %d list.\n\n",
    334  1.1      cgd 			rank0, ordin(rank0), ENTRYMAX);
    335  1.1      cgd 		}
    336  1.1      cgd 	}
    337  1.1      cgd 	if(rank0 == 0) rank0 = rank1;
    338  1.1      cgd 	if(rank0 <= 0) rank0 = rank;
    339  1.1      cgd 	if(!done_stopprint) outheader();
    340  1.1      cgd 	t1 = tt_head;
    341  1.1      cgd 	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
    342  1.1      cgd 	  if(flg) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n",
    343  1.1      cgd 	    t1->date, t1->uid,
    344  1.1      cgd 	    t1->level, t1->maxlvl,
    345  1.1      cgd 	    t1->hp, t1->maxhp, t1->points,
    346  1.1      cgd 	    t1->plchar, t1->sex, t1->name, t1->death);
    347  1.1      cgd 	  if(done_stopprint) continue;
    348  1.1      cgd 	  if(rank > flags.end_top &&
    349  1.1      cgd 	    (rank < rank0-flags.end_around || rank > rank0+flags.end_around)
    350  1.1      cgd 	    && (!flags.end_own ||
    351  1.1      cgd #ifdef PERS_IS_UID
    352  1.1      cgd 				  t1->uid != t0->uid ))
    353  1.1      cgd #else
    354  1.1      cgd 				  strncmp(t1->name, t0->name, NAMSZ)))
    355  1.1      cgd #endif PERS_IS_UID
    356  1.1      cgd 	  	continue;
    357  1.1      cgd 	  if(rank == rank0-flags.end_around &&
    358  1.1      cgd 	     rank0 > flags.end_top+flags.end_around+1 &&
    359  1.1      cgd 	     !flags.end_own)
    360  1.1      cgd 		(void) putchar('\n');
    361  1.1      cgd 	  if(rank != rank0)
    362  1.1      cgd 		(void) outentry(rank, t1, 0);
    363  1.1      cgd 	  else if(!rank1)
    364  1.1      cgd 		(void) outentry(rank, t1, 1);
    365  1.1      cgd 	  else {
    366  1.1      cgd 		int t0lth = outentry(0, t0, -1);
    367  1.1      cgd 		int t1lth = outentry(rank, t1, t0lth);
    368  1.1      cgd 		if(t1lth > t0lth) t0lth = t1lth;
    369  1.1      cgd 		(void) outentry(0, t0, t0lth);
    370  1.1      cgd 	  }
    371  1.1      cgd 	}
    372  1.1      cgd 	if(rank0 >= rank) if(!done_stopprint)
    373  1.1      cgd 		(void) outentry(0, t0, 1);
    374  1.1      cgd 	(void) fclose(rfile);
    375  1.1      cgd unlock:
    376  1.1      cgd 	(void) unlink(reclock);
    377  1.1      cgd }
    378  1.1      cgd 
    379  1.1      cgd outheader() {
    380  1.1      cgd char linebuf[BUFSZ];
    381  1.1      cgd register char *bp;
    382  1.1      cgd 	(void) strcpy(linebuf, "Number Points  Name");
    383  1.1      cgd 	bp = eos(linebuf);
    384  1.1      cgd 	while(bp < linebuf + COLNO - 9) *bp++ = ' ';
    385  1.1      cgd 	(void) strcpy(bp, "Hp [max]");
    386  1.1      cgd 	puts(linebuf);
    387  1.1      cgd }
    388  1.1      cgd 
    389  1.1      cgd /* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */
    390  1.1      cgd int
    391  1.1      cgd outentry(rank,t1,so) register struct toptenentry *t1; {
    392  1.1      cgd boolean quit = FALSE, killed = FALSE, starv = FALSE;
    393  1.1      cgd char linebuf[BUFSZ];
    394  1.1      cgd 	linebuf[0] = 0;
    395  1.1      cgd 	if(rank) Sprintf(eos(linebuf), "%3d", rank);
    396  1.1      cgd 		else Sprintf(eos(linebuf), "   ");
    397  1.1      cgd 	Sprintf(eos(linebuf), " %6ld %8s", t1->points, t1->name);
    398  1.1      cgd 	if(t1->plchar == 'X') Sprintf(eos(linebuf), " ");
    399  1.1      cgd 	else Sprintf(eos(linebuf), "-%c ", t1->plchar);
    400  1.1      cgd 	if(!strncmp("escaped", t1->death, 7)) {
    401  1.1      cgd 	  if(!strcmp(" (with amulet)", t1->death+7))
    402  1.1      cgd 	    Sprintf(eos(linebuf), "escaped the dungeon with amulet");
    403  1.1      cgd 	  else
    404  1.1      cgd 	    Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",
    405  1.1      cgd 	      t1->maxlvl);
    406  1.1      cgd 	} else {
    407  1.1      cgd 	  if(!strncmp(t1->death,"quit",4)) {
    408  1.1      cgd 	    quit = TRUE;
    409  1.1      cgd 	    if(t1->maxhp < 3*t1->hp && t1->maxlvl < 4)
    410  1.1      cgd 	  	Sprintf(eos(linebuf), "cravenly gave up");
    411  1.1      cgd 	    else
    412  1.1      cgd 		Sprintf(eos(linebuf), "quit");
    413  1.1      cgd 	  }
    414  1.1      cgd 	  else if(!strcmp(t1->death,"choked"))
    415  1.1      cgd 	    Sprintf(eos(linebuf), "choked on %s food",
    416  1.1      cgd 		(t1->sex == 'F') ? "her" : "his");
    417  1.1      cgd 	  else if(!strncmp(t1->death,"starv",5))
    418  1.1      cgd 	    Sprintf(eos(linebuf), "starved to death"), starv = TRUE;
    419  1.1      cgd 	  else Sprintf(eos(linebuf), "was killed"), killed = TRUE;
    420  1.1      cgd 	  Sprintf(eos(linebuf), " on%s level %d",
    421  1.1      cgd 	    (killed || starv) ? "" : " dungeon", t1->level);
    422  1.1      cgd 	  if(t1->maxlvl != t1->level)
    423  1.1      cgd 	    Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
    424  1.1      cgd 	  if(quit && t1->death[4]) Sprintf(eos(linebuf), t1->death + 4);
    425  1.1      cgd 	}
    426  1.1      cgd 	if(killed) Sprintf(eos(linebuf), " by %s%s",
    427  1.1      cgd 	  (!strncmp(t1->death, "trick", 5) || !strncmp(t1->death, "the ", 4))
    428  1.1      cgd 		? "" :
    429  1.1      cgd 	  index(vowels,*t1->death) ? "an " : "a ",
    430  1.1      cgd 	  t1->death);
    431  1.1      cgd 	Sprintf(eos(linebuf), ".");
    432  1.1      cgd 	if(t1->maxhp) {
    433  1.1      cgd 	  register char *bp = eos(linebuf);
    434  1.1      cgd 	  char hpbuf[10];
    435  1.1      cgd 	  int hppos;
    436  1.1      cgd 	  Sprintf(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-");
    437  1.1      cgd 	  hppos = COLNO - 7 - strlen(hpbuf);
    438  1.1      cgd 	  if(bp <= linebuf + hppos) {
    439  1.1      cgd 	    while(bp < linebuf + hppos) *bp++ = ' ';
    440  1.1      cgd 	    (void) strcpy(bp, hpbuf);
    441  1.1      cgd 	    Sprintf(eos(bp), " [%d]", t1->maxhp);
    442  1.1      cgd 	  }
    443  1.1      cgd 	}
    444  1.1      cgd 	if(so == 0) puts(linebuf);
    445  1.1      cgd 	else if(so > 0) {
    446  1.1      cgd 	  register char *bp = eos(linebuf);
    447  1.1      cgd 	  if(so >= COLNO) so = COLNO-1;
    448  1.1      cgd 	  while(bp < linebuf + so) *bp++ = ' ';
    449  1.1      cgd 	  *bp = 0;
    450  1.1      cgd 	  standoutbeg();
    451  1.1      cgd 	  fputs(linebuf,stdout);
    452  1.1      cgd 	  standoutend();
    453  1.1      cgd 	  (void) putchar('\n');
    454  1.1      cgd 	}
    455  1.1      cgd 	return(strlen(linebuf));
    456  1.1      cgd }
    457  1.1      cgd 
    458  1.1      cgd char *
    459  1.1      cgd itoa(a) int a; {
    460  1.1      cgd static char buf[12];
    461  1.1      cgd 	Sprintf(buf,"%d",a);
    462  1.1      cgd 	return(buf);
    463  1.1      cgd }
    464  1.1      cgd 
    465  1.1      cgd char *
    466  1.1      cgd ordin(n) int n; {
    467  1.1      cgd register int d = n%10;
    468  1.1      cgd 	return((d==0 || d>3 || n/10==1) ? "th" : (d==1) ? "st" :
    469  1.1      cgd 		(d==2) ? "nd" : "rd");
    470  1.1      cgd }
    471  1.1      cgd 
    472  1.1      cgd clearlocks(){
    473  1.1      cgd register x;
    474  1.1      cgd 	(void) signal(SIGHUP,SIG_IGN);
    475  1.1      cgd 	for(x = maxdlevel; x >= 0; x--) {
    476  1.1      cgd 		glo(x);
    477  1.1      cgd 		(void) unlink(lock);	/* not all levels need be present */
    478  1.1      cgd 	}
    479  1.1      cgd }
    480  1.1      cgd 
    481  1.1      cgd #ifdef NOSAVEONHANGUP
    482  1.1      cgd hangup()
    483  1.1      cgd {
    484  1.1      cgd 	(void) signal(SIGINT, SIG_IGN);
    485  1.1      cgd 	clearlocks();
    486  1.1      cgd 	exit(1);
    487  1.1      cgd }
    488  1.1      cgd #endif NOSAVEONHANGUP
    489  1.1      cgd 
    490  1.1      cgd char *
    491  1.1      cgd eos(s)
    492  1.1      cgd register char *s;
    493  1.1      cgd {
    494  1.1      cgd 	while(*s) s++;
    495  1.1      cgd 	return(s);
    496  1.1      cgd }
    497  1.1      cgd 
    498  1.1      cgd /* it is the callers responsibility to check that there is room for c */
    499  1.1      cgd charcat(s,c) register char *s, c; {
    500  1.1      cgd 	while(*s) s++;
    501  1.1      cgd 	*s++ = c;
    502  1.1      cgd 	*s = 0;
    503  1.1      cgd }
    504  1.1      cgd 
    505  1.1      cgd /*
    506  1.1      cgd  * Called with args from main if argc >= 0. In this case, list scores as
    507  1.1      cgd  * requested. Otherwise, find scores for the current player (and list them
    508  1.1      cgd  * if argc == -1).
    509  1.1      cgd  */
    510  1.1      cgd prscore(argc,argv) int argc; char **argv; {
    511  1.1      cgd 	extern char *hname;
    512  1.1      cgd 	char **players;
    513  1.1      cgd 	int playerct;
    514  1.1      cgd 	int rank;
    515  1.1      cgd 	register struct toptenentry *t1, *t2;
    516  1.1      cgd 	char *recfile = RECORD;
    517  1.1      cgd 	FILE *rfile;
    518  1.1      cgd 	register flg = 0;
    519  1.1      cgd 	register int i;
    520  1.1      cgd #ifdef nonsense
    521  1.1      cgd 	long total_score = 0L;
    522  1.1      cgd 	char totchars[10];
    523  1.1      cgd 	int totcharct = 0;
    524  1.1      cgd #endif nonsense
    525  1.1      cgd 	int outflg = (argc >= -1);
    526  1.1      cgd #ifdef PERS_IS_UID
    527  1.1      cgd 	int uid = -1;
    528  1.1      cgd #else
    529  1.1      cgd 	char *player0;
    530  1.1      cgd #endif PERS_IS_UID
    531  1.1      cgd 
    532  1.1      cgd 	if(!(rfile = fopen(recfile,"r"))){
    533  1.1      cgd 		puts("Cannot open record file!");
    534  1.1      cgd 		return;
    535  1.1      cgd 	}
    536  1.1      cgd 
    537  1.1      cgd 	if(argc > 1 && !strncmp(argv[1], "-s", 2)){
    538  1.1      cgd 		if(!argv[1][2]){
    539  1.1      cgd 			argc--;
    540  1.1      cgd 			argv++;
    541  1.1      cgd 		} else if(!argv[1][3] && index("CFKSTWX", argv[1][2])) {
    542  1.1      cgd 			argv[1]++;
    543  1.1      cgd 			argv[1][0] = '-';
    544  1.1      cgd 		} else	argv[1] += 2;
    545  1.1      cgd 	}
    546  1.1      cgd 	if(argc <= 1){
    547  1.1      cgd #ifdef PERS_IS_UID
    548  1.1      cgd 		uid = getuid();
    549  1.1      cgd 		playerct = 0;
    550  1.1      cgd #else
    551  1.1      cgd 		player0 = plname;
    552  1.1      cgd 		if(!*player0)
    553  1.1      cgd 			player0 = "hackplayer";
    554  1.1      cgd 		playerct = 1;
    555  1.1      cgd 		players = &player0;
    556  1.1      cgd #endif PERS_IS_UID
    557  1.1      cgd 	} else {
    558  1.1      cgd 		playerct = --argc;
    559  1.1      cgd 		players = ++argv;
    560  1.1      cgd 	}
    561  1.1      cgd 	if(outflg) putchar('\n');
    562  1.1      cgd 
    563  1.1      cgd 	t1 = tt_head = newttentry();
    564  1.1      cgd 	for(rank = 1; ; rank++) {
    565  1.1      cgd 	  if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
    566  1.1      cgd 		t1->date, &t1->uid,
    567  1.1      cgd 		&t1->level, &t1->maxlvl,
    568  1.1      cgd 		&t1->hp, &t1->maxhp, &t1->points,
    569  1.1      cgd 		&t1->plchar, &t1->sex, t1->name, t1->death) != 11)
    570  1.1      cgd 			t1->points = 0;
    571  1.1      cgd 	  if(t1->points == 0) break;
    572  1.1      cgd #ifdef PERS_IS_UID
    573  1.1      cgd 	  if(!playerct && t1->uid == uid)
    574  1.1      cgd 		flg++;
    575  1.1      cgd 	  else
    576  1.1      cgd #endif PERS_IS_UID
    577  1.1      cgd 	  for(i = 0; i < playerct; i++){
    578  1.1      cgd 		if(strcmp(players[i], "all") == 0 ||
    579  1.1      cgd 		   strncmp(t1->name, players[i], NAMSZ) == 0 ||
    580  1.1      cgd 		  (players[i][0] == '-' &&
    581  1.1      cgd 		   players[i][1] == t1->plchar &&
    582  1.1      cgd 		   players[i][2] == 0) ||
    583  1.1      cgd 		  (digit(players[i][0]) && rank <= atoi(players[i])))
    584  1.1      cgd 			flg++;
    585  1.1      cgd 	  }
    586  1.1      cgd 	  t1 = t1->tt_next = newttentry();
    587  1.1      cgd 	}
    588  1.1      cgd 	(void) fclose(rfile);
    589  1.1      cgd 	if(!flg) {
    590  1.1      cgd 	    if(outflg) {
    591  1.1      cgd 		printf("Cannot find any entries for ");
    592  1.1      cgd 		if(playerct < 1) printf("you.\n");
    593  1.1      cgd 		else {
    594  1.1      cgd 		  if(playerct > 1) printf("any of ");
    595  1.1      cgd 		  for(i=0; i<playerct; i++)
    596  1.1      cgd 			printf("%s%s", players[i], (i<playerct-1)?", ":".\n");
    597  1.1      cgd 		  printf("Call is: %s -s [playernames]\n", hname);
    598  1.1      cgd 		}
    599  1.1      cgd 	    }
    600  1.1      cgd 	    return;
    601  1.1      cgd 	}
    602  1.1      cgd 
    603  1.1      cgd 	if(outflg) outheader();
    604  1.1      cgd 	t1 = tt_head;
    605  1.1      cgd 	for(rank = 1; t1->points != 0; rank++, t1 = t2) {
    606  1.1      cgd 		t2 = t1->tt_next;
    607  1.1      cgd #ifdef PERS_IS_UID
    608  1.1      cgd 		if(!playerct && t1->uid == uid)
    609  1.1      cgd 			goto outwithit;
    610  1.1      cgd 		else
    611  1.1      cgd #endif PERS_IS_UID
    612  1.1      cgd 		for(i = 0; i < playerct; i++){
    613  1.1      cgd 			if(strcmp(players[i], "all") == 0 ||
    614  1.1      cgd 			   strncmp(t1->name, players[i], NAMSZ) == 0 ||
    615  1.1      cgd 			  (players[i][0] == '-' &&
    616  1.1      cgd 			   players[i][1] == t1->plchar &&
    617  1.1      cgd 			   players[i][2] == 0) ||
    618  1.1      cgd 			  (digit(players[i][0]) && rank <= atoi(players[i]))){
    619  1.1      cgd 			outwithit:
    620  1.1      cgd 				if(outflg)
    621  1.1      cgd 				    (void) outentry(rank, t1, 0);
    622  1.1      cgd #ifdef nonsense
    623  1.1      cgd 				total_score += t1->points;
    624  1.1      cgd 				if(totcharct < sizeof(totchars)-1)
    625  1.1      cgd 				    totchars[totcharct++] = t1->plchar;
    626  1.1      cgd #endif nonsense
    627  1.1      cgd 				break;
    628  1.1      cgd 			}
    629  1.1      cgd 		}
    630  1.1      cgd 		free((char *) t1);
    631  1.1      cgd 	}
    632  1.1      cgd #ifdef nonsense
    633  1.1      cgd 	totchars[totcharct] = 0;
    634  1.1      cgd 
    635  1.1      cgd 	/* We would like to determine whether he is experienced. However,
    636  1.1      cgd 	   the information collected here only tells about the scores/roles
    637  1.1      cgd 	   that got into the topten (top 100?). We should maintain a
    638  1.1      cgd 	   .hacklog or something in his home directory. */
    639  1.1      cgd 	flags.beginner = (total_score < 6000);
    640  1.1      cgd 	for(i=0; i<6; i++)
    641  1.1      cgd 	    if(!index(totchars, "CFKSTWX"[i])) {
    642  1.1      cgd 		flags.beginner = 1;
    643  1.1      cgd 		if(!pl_character[0]) pl_character[0] = "CFKSTWX"[i];
    644  1.1      cgd 		break;
    645  1.1      cgd 	}
    646  1.1      cgd #endif nonsense
    647  1.1      cgd }
    648