Home | History | Annotate | Line # | Download | only in larn
scores.c revision 1.17
      1  1.17  dholland /*	$NetBSD: scores.c,v 1.17 2008/02/03 20:41:53 dholland Exp $	*/
      2   1.3   mycroft 
      3  1.10  christos /*
      4  1.10  christos  * scores.c			 Larn is copyrighted 1986 by Noah Morgan.
      5  1.10  christos  *
      6  1.10  christos  * Functions in this file are:
      7  1.10  christos  *
      8  1.10  christos  * readboard() 	Function to read in the scoreboard into a static buffer
      9  1.10  christos  * writeboard()	Function to write the scoreboard from readboard()'s buffer
     10  1.10  christos  * makeboard() 	Function to create a new scoreboard (wipe out old one)
     11  1.10  christos  * hashewon()	 Function to return 1 if player has won a game before, else 0
     12  1.10  christos  * long paytaxes(x)	 Function to pay taxes if any are due winshou()
     13  1.10  christos  * ubroutine to print out the winning scoreboard shou(x)
     14  1.10  christos  * ubroutine to print out the non-winners scoreboard showscores()
     15  1.10  christos  * unction to show the scoreboard on the terminal showallscores()
     16  1.10  christos  * Function to show scores and the iven lists that go with them sortboard()
     17  1.10  christos  * unction to sort the scoreboard newscore(score, whoo, whyded, winner)
     18  1.10  christos  * Function to add entry to scoreboard new1sub(score,i,whoo,taxes)
     19  1.10  christos  * Subroutine to put player into a new2sub(score,i,whoo,whyded)
     20  1.10  christos  * Subroutine to put player into a died(x) 	Subroutine to record who
     21  1.10  christos  * played larn, and what the score was diedsub(x) Subroutine to print out a
     22  1.10  christos  * line showing player when he is killed diedlog() 	Subroutine to read a
     23  1.10  christos  * log file and print it out in ascii format getplid(name)
     24  1.10  christos  * on to get players id # from id file
     25  1.10  christos  *
     26   1.1       cgd  */
     27  1.10  christos #include <sys/cdefs.h>
     28  1.10  christos #ifndef lint
     29  1.17  dholland __RCSID("$NetBSD: scores.c,v 1.17 2008/02/03 20:41:53 dholland Exp $");
     30  1.10  christos #endif				/* not lint */
     31   1.1       cgd #include <sys/types.h>
     32   1.1       cgd #include <sys/times.h>
     33   1.1       cgd #include <sys/stat.h>
     34  1.10  christos #include <stdio.h>
     35  1.10  christos #include <string.h>
     36  1.10  christos #include <unistd.h>
     37  1.10  christos #include <stdlib.h>
     38   1.1       cgd #include "header.h"
     39  1.10  christos #include "extern.h"
     40   1.1       cgd 
     41  1.10  christos struct scofmt {			/* This is the structure for the scoreboard 		 */
     42  1.10  christos 	long            score;	/* the score of the player 							 */
     43  1.10  christos 	long            suid;	/* the user id number of the player 				 */
     44  1.10  christos 	short           what;	/* the number of the monster that killed
     45  1.10  christos 				 * player 	 */
     46  1.10  christos 	short           level;	/* the level player was on when he died 			 */
     47  1.10  christos 	short           hardlev;/* the level of difficulty player played at 		 */
     48  1.10  christos 	short           order;	/* the relative ordering place of this entry 		 */
     49  1.10  christos 	char            who[40];/* the name of the character 						 */
     50  1.10  christos 	char            sciv[26][2];	/* this is the inventory list of the
     51  1.10  christos 					 * character 		 */
     52  1.10  christos };
     53  1.10  christos struct wscofmt {		/* This is the structure for the winning
     54  1.10  christos 				 * scoreboard */
     55  1.10  christos 	long            score;	/* the score of the player 							 */
     56  1.10  christos 	long            timeused;	/* the time used in mobuls to win the
     57  1.10  christos 					 * game 			 */
     58  1.10  christos 	long            taxes;	/* taxes he owes to LRS 							 */
     59  1.10  christos 	long            suid;	/* the user id number of the player 				 */
     60  1.10  christos 	short           hardlev;/* the level of difficulty player played at 		 */
     61  1.10  christos 	short           order;	/* the relative ordering place of this entry 		 */
     62  1.10  christos 	char            who[40];/* the name of the character 						 */
     63  1.10  christos };
     64  1.10  christos 
     65  1.10  christos struct log_fmt {		/* 102 bytes struct for the log file 				 */
     66  1.10  christos 	long            score;	/* the players score 								 */
     67  1.10  christos 	time_t          diedtime;	/* time when game was over 							 */
     68  1.10  christos 	short           cavelev;/* level in caves 									 */
     69  1.10  christos 	short           diff;	/* difficulty player played at 						 */
     70   1.1       cgd #ifdef EXTRA
     71  1.10  christos 	long            elapsedtime;	/* real time of game in seconds 					 */
     72  1.10  christos 	long            bytout;	/* bytes input and output 							 */
     73  1.10  christos 	long            bytin;
     74  1.10  christos 	long            moves;	/* number of moves made by player 					 */
     75  1.10  christos 	short           ac;	/* armor class of player 							 */
     76  1.10  christos 	short           hp, hpmax;	/* players hitpoints 								 */
     77  1.12       wiz 	short           cputime;/* CPU time needed in seconds 						 */
     78  1.10  christos 	short           killed, spused;	/* monsters killed and spells cast 					 */
     79  1.12       wiz 	short           usage;	/* usage of the CPU in % 							 */
     80  1.10  christos 	short           lev;	/* player level 									 */
     81   1.1       cgd #endif
     82  1.10  christos 	char            who[12];/* player name 										 */
     83  1.10  christos 	char            what[46];	/* what happened to player 							 */
     84  1.10  christos };
     85   1.1       cgd 
     86   1.1       cgd static struct scofmt sco[SCORESIZE];	/* the structure for the scoreboard  */
     87   1.1       cgd static struct wscofmt winr[SCORESIZE];	/* struct for the winning scoreboard */
     88  1.10  christos static struct log_fmt logg;	/* structure for the log file 		 */
     89  1.15  dholland static const char *whydead[] = {
     90   1.1       cgd 	"quit", "suspended", "self - annihilated", "shot by an arrow",
     91   1.1       cgd 	"hit by a dart", "fell into a pit", "fell into a bottomless pit",
     92   1.1       cgd 	"a winner", "trapped in solid rock", "killed by a missing save file",
     93   1.1       cgd 	"killed by an old save file", "caught by the greedy cheater checker trap",
     94  1.10  christos 	"killed by a protected save file", "killed his family and committed suicide",
     95   1.1       cgd 	"erased by a wayward finger", "fell through a bottomless trap door",
     96   1.1       cgd 	"fell through a trap door", "drank some poisonous water",
     97   1.1       cgd 	"fried by an electric shock", "slipped on a volcano shaft",
     98   1.1       cgd 	"killed by a stupid act of frustration", "attacked by a revolting demon",
     99   1.1       cgd 	"hit by his own magic", "demolished by an unseen attacker",
    100   1.1       cgd 	"fell into the dreadful sleep", "killed by an exploding chest",
    101  1.10  christos 	 /* 26 */ "killed by a missing maze data file", "annihilated in a sphere",
    102  1.10  christos 	"died a post mortem death", "wasted by a malloc() failure"
    103  1.10  christos };
    104   1.1       cgd 
    105   1.1       cgd /*
    106  1.10  christos  * readboard() 	Function to read in the scoreboard into a static buffer
    107   1.1       cgd  *
    108  1.10  christos  * returns -1 if unable to read in the scoreboard, returns 0 if all is OK
    109   1.1       cgd  */
    110  1.10  christos int
    111   1.1       cgd readboard()
    112  1.10  christos {
    113  1.10  christos 	int             i;
    114   1.6       mrg 
    115  1.16  dholland 	if (gid != egid)
    116  1.16  dholland 		setegid(egid);
    117   1.6       mrg 	i = lopen(scorefile);
    118  1.16  dholland 	if (gid != egid)
    119  1.16  dholland 		setegid(gid);
    120  1.10  christos 	if (i < 0) {
    121  1.10  christos 		lprcat("Can't read scoreboard\n");
    122  1.10  christos 		lflush();
    123  1.10  christos 		return (-1);
    124   1.1       cgd 	}
    125  1.10  christos 	lrfill((char *) sco, sizeof(sco));
    126  1.10  christos 	lrfill((char *) winr, sizeof(winr));
    127  1.10  christos 	lrclose();
    128  1.10  christos 	lcreat((char *) 0);
    129  1.10  christos 	return (0);
    130  1.10  christos }
    131   1.1       cgd 
    132   1.1       cgd /*
    133  1.10  christos  * writeboard()	Function to write the scoreboard from readboard()'s buffer
    134   1.1       cgd  *
    135  1.10  christos  * returns -1 if unable to write the scoreboard, returns 0 if all is OK
    136   1.1       cgd  */
    137  1.10  christos int
    138   1.1       cgd writeboard()
    139  1.10  christos {
    140  1.10  christos 	int             i;
    141   1.6       mrg 
    142   1.1       cgd 	set_score_output();
    143  1.16  dholland 	if (gid != egid)
    144  1.16  dholland 		setegid(egid);
    145   1.6       mrg 	i = lcreat(scorefile);
    146  1.16  dholland 	if (gid != egid)
    147  1.16  dholland 		setegid(gid);
    148  1.10  christos 	if (i < 0) {
    149  1.10  christos 		lprcat("Can't write scoreboard\n");
    150  1.10  christos 		lflush();
    151  1.10  christos 		return (-1);
    152   1.1       cgd 	}
    153  1.10  christos 	lwrite((char *) sco, sizeof(sco));
    154  1.10  christos 	lwrite((char *) winr, sizeof(winr));
    155  1.10  christos 	lwclose();
    156  1.10  christos 	lcreat((char *) 0);
    157  1.10  christos 	return (0);
    158  1.10  christos }
    159   1.1       cgd 
    160   1.1       cgd /*
    161  1.10  christos  * makeboard() 		Function to create a new scoreboard (wipe out old one)
    162   1.1       cgd  *
    163  1.10  christos  * returns -1 if unable to write the scoreboard, returns 0 if all is OK
    164   1.1       cgd  */
    165  1.10  christos int
    166   1.1       cgd makeboard()
    167  1.10  christos {
    168  1.10  christos 	int    i;
    169  1.13     mouse 	set_score_output();
    170  1.10  christos 	for (i = 0; i < SCORESIZE; i++) {
    171   1.1       cgd 		winr[i].taxes = winr[i].score = sco[i].score = 0;
    172   1.1       cgd 		winr[i].order = sco[i].order = i;
    173  1.10  christos 	}
    174  1.10  christos 	if (writeboard())
    175  1.10  christos 		return (-1);
    176  1.16  dholland 	if (gid != egid)
    177  1.16  dholland 		setegid(egid);
    178  1.10  christos 	chmod(scorefile, 0660);
    179  1.16  dholland 	if (gid != egid)
    180  1.16  dholland 		setegid(gid);
    181  1.10  christos 	return (0);
    182  1.10  christos }
    183   1.1       cgd 
    184   1.1       cgd /*
    185  1.10  christos  * hashewon()	 Function to return 1 if player has won a game before, else 0
    186   1.1       cgd  *
    187  1.10  christos  * This function also sets c[HARDGAME] to appropriate value -- 0 if not a
    188  1.10  christos  * winner, otherwise the next level of difficulty listed in the winners
    189  1.10  christos  * scoreboard.  This function also sets outstanding_taxes to the value in
    190  1.10  christos  * the winners scoreboard.
    191   1.1       cgd  */
    192  1.10  christos int
    193   1.1       cgd hashewon()
    194  1.10  christos {
    195  1.10  christos 	int    i;
    196   1.1       cgd 	c[HARDGAME] = 0;
    197  1.10  christos 	if (readboard() < 0)
    198  1.10  christos 		return (0);	/* can't find scoreboard */
    199  1.10  christos 	for (i = 0; i < SCORESIZE; i++)	/* search through winners scoreboard */
    200  1.10  christos 		if (winr[i].suid == userid)
    201  1.10  christos 			if (winr[i].score > 0) {
    202  1.10  christos 				c[HARDGAME] = winr[i].hardlev + 1;
    203  1.10  christos 				outstanding_taxes = winr[i].taxes;
    204  1.10  christos 				return (1);
    205   1.1       cgd 			}
    206  1.10  christos 	return (0);
    207  1.10  christos }
    208   1.1       cgd 
    209   1.1       cgd /*
    210  1.10  christos  * long paytaxes(x)		 Function to pay taxes if any are due
    211   1.1       cgd  *
    212  1.10  christos  * Enter with the amount (in gp) to pay on the taxes.
    213  1.10  christos  * Returns amount actually paid.
    214   1.1       cgd  */
    215  1.10  christos long
    216  1.10  christos paytaxes(x)
    217  1.10  christos 	long            x;
    218  1.10  christos {
    219  1.10  christos 	int    i;
    220  1.10  christos 	long   amt;
    221  1.10  christos 	if (x < 0)
    222  1.10  christos 		return (0L);
    223  1.10  christos 	if (readboard() < 0)
    224  1.10  christos 		return (0L);
    225  1.10  christos 	for (i = 0; i < SCORESIZE; i++)
    226  1.10  christos 		if (winr[i].suid == userid)	/* look for players winning
    227  1.10  christos 						 * entry */
    228  1.10  christos 			if (winr[i].score > 0) {	/* search for a winning
    229  1.10  christos 							 * entry for the player */
    230   1.1       cgd 				amt = winr[i].taxes;
    231  1.10  christos 				if (x < amt)
    232  1.10  christos 					amt = x;	/* don't overpay taxes
    233  1.10  christos 							 * (Ughhhhh) */
    234   1.1       cgd 				winr[i].taxes -= amt;
    235   1.1       cgd 				outstanding_taxes -= amt;
    236  1.13     mouse 				set_score_output();
    237  1.10  christos 				if (writeboard() < 0)
    238  1.10  christos 					return (0);
    239  1.10  christos 				return (amt);
    240  1.10  christos 			}
    241  1.10  christos 	return (0L);		/* couldn't find user on winning scoreboard */
    242  1.10  christos }
    243   1.1       cgd 
    244   1.1       cgd /*
    245  1.10  christos  * winshou()		Subroutine to print out the winning scoreboard
    246   1.1       cgd  *
    247  1.10  christos  * Returns the number of players on scoreboard that were shown
    248   1.1       cgd  */
    249  1.10  christos int
    250   1.1       cgd winshou()
    251  1.10  christos {
    252  1.10  christos 	struct wscofmt *p;
    253  1.10  christos 	int    i, j, count;
    254  1.10  christos 	for (count = j = i = 0; i < SCORESIZE; i++)	/* is there anyone on
    255  1.10  christos 							 * the scoreboard? */
    256  1.10  christos 		if (winr[i].score != 0) {
    257  1.10  christos 			j++;
    258  1.10  christos 			break;
    259  1.10  christos 		}
    260  1.10  christos 	if (j) {
    261   1.1       cgd 		lprcat("\n  Score    Difficulty   Time Needed   Larn Winners List\n");
    262   1.1       cgd 
    263  1.10  christos 		for (i = 0; i < SCORESIZE; i++)	/* this loop is needed to
    264  1.10  christos 						 * print out the */
    265  1.10  christos 			for (j = 0; j < SCORESIZE; j++) {	/* winners in order */
    266  1.10  christos 				p = &winr[j];	/* pointer to the scoreboard
    267  1.10  christos 						 * entry */
    268  1.10  christos 				if (p->order == i) {
    269  1.10  christos 					if (p->score) {
    270  1.10  christos 						count++;
    271  1.14  dholland 						lprintf("%10ld     %2ld      %5ld Mobuls   %s \n",
    272  1.10  christos 							(long) p->score, (long) p->hardlev, (long) p->timeused, p->who);
    273   1.1       cgd 					}
    274  1.10  christos 					break;
    275   1.1       cgd 				}
    276   1.1       cgd 			}
    277   1.1       cgd 	}
    278  1.10  christos 	return (count);		/* return number of people on scoreboard */
    279  1.10  christos }
    280   1.1       cgd 
    281   1.1       cgd /*
    282  1.10  christos  * shou(x)			Subroutine to print out the non-winners scoreboard
    283  1.10  christos  * 	int x;
    284   1.1       cgd  *
    285  1.10  christos  * Enter with 0 to list the scores, enter with 1 to list inventories too
    286  1.10  christos  * Returns the number of players on scoreboard that were shown
    287   1.1       cgd  */
    288  1.10  christos int
    289   1.1       cgd shou(x)
    290  1.10  christos 	int             x;
    291  1.10  christos {
    292  1.10  christos 	int    i, j, n, k;
    293  1.10  christos 	int             count;
    294  1.10  christos 	for (count = j = i = 0; i < SCORESIZE; i++)	/* is the scoreboard
    295  1.10  christos 							 * empty? */
    296  1.10  christos 		if (sco[i].score != 0) {
    297  1.10  christos 			j++;
    298  1.10  christos 			break;
    299  1.10  christos 		}
    300  1.10  christos 	if (j) {
    301   1.1       cgd 		lprcat("\n   Score   Difficulty   Larn Visitor Log\n");
    302  1.10  christos 		for (i = 0; i < SCORESIZE; i++)	/* be sure to print them out
    303  1.10  christos 						 * in order */
    304  1.10  christos 			for (j = 0; j < SCORESIZE; j++)
    305  1.10  christos 				if (sco[j].order == i) {
    306  1.10  christos 					if (sco[j].score) {
    307  1.10  christos 						count++;
    308  1.14  dholland 						lprintf("%10ld     %2ld       %s ",
    309  1.10  christos 							(long) sco[j].score, (long) sco[j].hardlev, sco[j].who);
    310  1.10  christos 						if (sco[j].what < 256)
    311  1.10  christos 							lprintf("killed by a %s", monster[sco[j].what].name);
    312  1.10  christos 						else
    313  1.10  christos 							lprintf("%s", whydead[sco[j].what - 256]);
    314  1.10  christos 						if (x != 263)
    315  1.10  christos 							lprintf(" on %s", levelname[sco[j].level]);
    316  1.10  christos 						if (x) {
    317  1.10  christos 							for (n = 0; n < 26; n++) {
    318  1.10  christos 								iven[n] = sco[j].sciv[n][0];
    319  1.10  christos 								ivenarg[n] = sco[j].sciv[n][1];
    320  1.10  christos 							}
    321  1.10  christos 							for (k = 1; k < 99; k++)
    322  1.10  christos 								for (n = 0; n < 26; n++)
    323  1.10  christos 									if (k == iven[n]) {
    324  1.10  christos 										srcount = 0;
    325  1.10  christos 										show3(n);
    326  1.10  christos 									}
    327  1.10  christos 							lprcat("\n\n");
    328  1.10  christos 						} else
    329  1.10  christos 							lprc('\n');
    330   1.1       cgd 					}
    331  1.10  christos 					j = SCORESIZE;
    332   1.1       cgd 				}
    333   1.1       cgd 	}
    334  1.10  christos 	return (count);		/* return the number of players just shown */
    335  1.10  christos }
    336   1.1       cgd 
    337   1.1       cgd /*
    338  1.10  christos  * showscores()		Function to show the scoreboard on the terminal
    339   1.1       cgd  *
    340  1.10  christos  * Returns nothing of value
    341   1.1       cgd  */
    342  1.10  christos static char     esb[] = "The scoreboard is empty.\n";
    343  1.10  christos void
    344   1.1       cgd showscores()
    345  1.10  christos {
    346  1.10  christos 	int    i, j;
    347   1.1       cgd 	lflush();
    348  1.10  christos 	lcreat((char *) 0);
    349  1.10  christos 	if (readboard() < 0)
    350  1.10  christos 		return;
    351  1.10  christos 	i = winshou();
    352  1.10  christos 	j = shou(0);
    353  1.10  christos 	if (i + j == 0)
    354  1.10  christos 		lprcat(esb);
    355  1.10  christos 	else
    356  1.10  christos 		lprc('\n');
    357  1.10  christos 	lflush();
    358  1.10  christos }
    359   1.1       cgd 
    360   1.1       cgd /*
    361  1.10  christos  * showallscores()	Function to show scores and the iven lists that go with them
    362   1.1       cgd  *
    363  1.10  christos  * Returns nothing of value
    364   1.1       cgd  */
    365  1.10  christos void
    366   1.1       cgd showallscores()
    367  1.10  christos {
    368  1.10  christos 	int    i, j;
    369   1.1       cgd 	lflush();
    370  1.10  christos 	lcreat((char *) 0);
    371  1.10  christos 	if (readboard() < 0)
    372  1.10  christos 		return;
    373  1.10  christos 	c[WEAR] = c[WIELD] = c[SHIELD] = -1;	/* not wielding or wearing
    374  1.10  christos 						 * anything */
    375  1.10  christos 	for (i = 0; i < MAXPOTION; i++)
    376  1.10  christos 		potionname[i] = potionhide[i];
    377  1.10  christos 	for (i = 0; i < MAXSCROLL; i++)
    378  1.10  christos 		scrollname[i] = scrollhide[i];
    379  1.10  christos 	i = winshou();
    380  1.10  christos 	j = shou(1);
    381  1.10  christos 	if (i + j == 0)
    382  1.10  christos 		lprcat(esb);
    383  1.10  christos 	else
    384  1.10  christos 		lprc('\n');
    385  1.10  christos 	lflush();
    386  1.10  christos }
    387   1.1       cgd 
    388   1.1       cgd /*
    389  1.10  christos  * sortboard()		Function to sort the scoreboard
    390   1.1       cgd  *
    391  1.10  christos  * Returns 0 if no sorting done, else returns 1
    392   1.1       cgd  */
    393  1.10  christos int
    394   1.1       cgd sortboard()
    395  1.10  christos {
    396  1.10  christos 	int    i, j = 0, pos;
    397  1.10  christos 	long            jdat;
    398  1.10  christos 	for (i = 0; i < SCORESIZE; i++)
    399  1.10  christos 		sco[i].order = winr[i].order = -1;
    400  1.10  christos 	pos = 0;
    401  1.10  christos 	while (pos < SCORESIZE) {
    402  1.10  christos 		jdat = 0;
    403  1.10  christos 		for (i = 0; i < SCORESIZE; i++)
    404  1.10  christos 			if ((sco[i].order < 0) && (sco[i].score >= jdat)) {
    405  1.10  christos 				j = i;
    406  1.10  christos 				jdat = sco[i].score;
    407  1.10  christos 			}
    408   1.1       cgd 		sco[j].order = pos++;
    409  1.10  christos 	}
    410  1.10  christos 	pos = 0;
    411  1.10  christos 	while (pos < SCORESIZE) {
    412  1.10  christos 		jdat = 0;
    413  1.10  christos 		for (i = 0; i < SCORESIZE; i++)
    414  1.10  christos 			if ((winr[i].order < 0) && (winr[i].score >= jdat)) {
    415  1.10  christos 				j = i;
    416  1.10  christos 				jdat = winr[i].score;
    417  1.10  christos 			}
    418   1.1       cgd 		winr[j].order = pos++;
    419   1.1       cgd 	}
    420  1.10  christos 	return (1);
    421  1.10  christos }
    422   1.1       cgd 
    423   1.1       cgd /*
    424  1.10  christos  * newscore(score, whoo, whyded, winner) 	Function to add entry to scoreboard
    425  1.10  christos  * 	int score, winner, whyded;
    426  1.10  christos  * 	char *whoo;
    427   1.1       cgd  *
    428  1.10  christos  * Enter with the total score in gp in score,  players name in whoo,
    429  1.10  christos  * 	died() reason # in whyded, and TRUE/FALSE in winner if a winner
    430  1.10  christos  * ex.		newscore(1000, "player 1", 32, 0);
    431   1.1       cgd  */
    432  1.10  christos void
    433   1.1       cgd newscore(score, whoo, whyded, winner)
    434  1.10  christos 	long            score;
    435  1.10  christos 	int             winner, whyded;
    436  1.10  christos 	char           *whoo;
    437  1.10  christos {
    438  1.10  christos 	int    i;
    439  1.10  christos 	long            taxes;
    440  1.10  christos 	if (readboard() < 0)
    441  1.10  christos 		return;		/* do the scoreboard	 */
    442   1.1       cgd 	/* if a winner then delete all non-winning scores */
    443  1.10  christos 	if (cheat)
    444  1.10  christos 		winner = 0;	/* if he cheated, don't let him win */
    445  1.10  christos 	if (winner) {
    446  1.10  christos 		for (i = 0; i < SCORESIZE; i++)
    447  1.10  christos 			if (sco[i].suid == userid)
    448  1.10  christos 				sco[i].score = 0;
    449  1.10  christos 		taxes = score * TAXRATE;
    450  1.10  christos 		score += 100000 * c[HARDGAME];	/* bonus for winning */
    451  1.10  christos 		/*
    452  1.10  christos 		 * if he has a slot on the winning scoreboard update it if
    453  1.10  christos 		 * greater score
    454  1.10  christos 		 */
    455  1.10  christos 		for (i = 0; i < SCORESIZE; i++)
    456  1.10  christos 			if (winr[i].suid == userid) {
    457  1.10  christos 				new1sub(score, i, whoo, taxes);
    458  1.10  christos 				return;
    459  1.10  christos 			}
    460  1.10  christos 		/*
    461  1.10  christos 		 * he had no entry. look for last entry and see if he has a
    462  1.10  christos 		 * greater score
    463  1.10  christos 		 */
    464  1.10  christos 		for (i = 0; i < SCORESIZE; i++)
    465  1.10  christos 			if (winr[i].order == SCORESIZE - 1) {
    466  1.10  christos 				new1sub(score, i, whoo, taxes);
    467  1.10  christos 				return;
    468  1.10  christos 			}
    469  1.10  christos 	} else if (!cheat) {	/* for not winning scoreboard */
    470  1.10  christos 		/*
    471  1.10  christos 		 * if he has a slot on the scoreboard update it if greater
    472  1.10  christos 		 * score
    473  1.10  christos 		 */
    474  1.10  christos 		for (i = 0; i < SCORESIZE; i++)
    475  1.10  christos 			if (sco[i].suid == userid) {
    476  1.10  christos 				new2sub(score, i, whoo, whyded);
    477  1.10  christos 				return;
    478  1.10  christos 			}
    479  1.10  christos 		/*
    480  1.10  christos 		 * he had no entry. look for last entry and see if he has a
    481  1.10  christos 		 * greater score
    482  1.10  christos 		 */
    483  1.10  christos 		for (i = 0; i < SCORESIZE; i++)
    484  1.10  christos 			if (sco[i].order == SCORESIZE - 1) {
    485  1.10  christos 				new2sub(score, i, whoo, whyded);
    486  1.10  christos 				return;
    487  1.10  christos 			}
    488   1.1       cgd 	}
    489  1.10  christos }
    490   1.1       cgd 
    491   1.1       cgd /*
    492  1.10  christos  * new1sub(score,i,whoo,taxes) 	  Subroutine to put player into a
    493  1.10  christos  * 	int score,i,whyded,taxes;		  winning scoreboard entry if his score
    494  1.10  christos  * 	char *whoo; 					  is high enough
    495  1.10  christos  *
    496  1.10  christos  * Enter with the total score in gp in score,  players name in whoo,
    497  1.10  christos  * 	died() reason # in whyded, and TRUE/FALSE in winner if a winner
    498  1.10  christos  * 	slot in scoreboard in i, and the tax bill in taxes.
    499  1.10  christos  * Returns nothing of value
    500  1.10  christos  */
    501  1.10  christos void
    502  1.10  christos new1sub(score, i, whoo, taxes)
    503  1.10  christos 	long            score, taxes;
    504  1.10  christos 	int             i;
    505  1.10  christos 	char           *whoo;
    506  1.10  christos {
    507  1.10  christos 	struct wscofmt *p;
    508   1.1       cgd 	p = &winr[i];
    509   1.1       cgd 	p->taxes += taxes;
    510  1.10  christos 	if ((score >= p->score) || (c[HARDGAME] > p->hardlev)) {
    511  1.10  christos 		strcpy(p->who, whoo);
    512  1.10  christos 		p->score = score;
    513  1.10  christos 		p->hardlev = c[HARDGAME];
    514  1.10  christos 		p->suid = userid;
    515  1.10  christos 		p->timeused = gltime / 100;
    516  1.10  christos 	}
    517  1.10  christos }
    518  1.10  christos 
    519  1.10  christos /*
    520  1.10  christos  * new2sub(score,i,whoo,whyded)	 	  Subroutine to put player into a
    521  1.10  christos  * 	int score,i,whyded,taxes;		  non-winning scoreboard entry if his
    522  1.10  christos  * 	char *whoo; 					  score is high enough
    523  1.10  christos  *
    524  1.10  christos  * Enter with the total score in gp in score,  players name in whoo,
    525  1.10  christos  * 	died() reason # in whyded, and slot in scoreboard in i.
    526  1.10  christos  * Returns nothing of value
    527  1.10  christos  */
    528  1.10  christos void
    529  1.10  christos new2sub(score, i, whoo, whyded)
    530  1.10  christos 	long            score;
    531  1.10  christos 	int             i, whyded;
    532  1.10  christos 	char           *whoo;
    533  1.10  christos {
    534  1.10  christos 	int    j;
    535  1.10  christos 	struct scofmt *p;
    536   1.1       cgd 	p = &sco[i];
    537  1.10  christos 	if ((score >= p->score) || (c[HARDGAME] > p->hardlev)) {
    538  1.10  christos 		strcpy(p->who, whoo);
    539  1.10  christos 		p->score = score;
    540  1.10  christos 		p->what = whyded;
    541  1.10  christos 		p->hardlev = c[HARDGAME];
    542  1.10  christos 		p->suid = userid;
    543  1.10  christos 		p->level = level;
    544  1.10  christos 		for (j = 0; j < 26; j++) {
    545  1.10  christos 			p->sciv[j][0] = iven[j];
    546  1.10  christos 			p->sciv[j][1] = ivenarg[j];
    547  1.10  christos 		}
    548  1.10  christos 	}
    549  1.10  christos }
    550  1.10  christos 
    551  1.10  christos /*
    552  1.10  christos  * died(x) 	Subroutine to record who played larn, and what the score was
    553  1.10  christos  * 	int x;
    554  1.10  christos  *
    555  1.10  christos  * if x < 0 then don't show scores
    556  1.10  christos  * died() never returns! (unless c[LIFEPROT] and a reincarnatable death!)
    557  1.10  christos  *
    558  1.10  christos  * 	< 256	killed by the monster number
    559  1.10  christos  * 	256		quit
    560  1.10  christos  * 	257		suspended
    561  1.10  christos  * 	258		self - annihilated
    562  1.10  christos  * 	259		shot by an arrow
    563  1.10  christos  * 	260		hit by a dart
    564  1.10  christos  * 	261		fell into a pit
    565  1.10  christos  * 	262		fell into a bottomless pit
    566  1.10  christos  * 	263		a winner
    567  1.10  christos  * 	264		trapped in solid rock
    568  1.10  christos  * 	265		killed by a missing save file
    569  1.10  christos  * 	266		killed by an old save file
    570  1.10  christos  * 	267		caught by the greedy cheater checker trap
    571  1.10  christos  * 	268		killed by a protected save file
    572  1.10  christos  * 	269		killed his family and killed himself
    573  1.10  christos  * 	270		erased by a wayward finger
    574  1.10  christos  * 	271		fell through a bottomless trap door
    575  1.10  christos  * 	272		fell through a trap door
    576  1.10  christos  * 	273		drank some poisonous water
    577  1.10  christos  * 	274		fried by an electric shock
    578  1.10  christos  * 	275		slipped on a volcano shaft
    579  1.10  christos  * 	276		killed by a stupid act of frustration
    580  1.10  christos  * 	277		attacked by a revolting demon
    581  1.10  christos  * 	278		hit by his own magic
    582  1.10  christos  * 	279		demolished by an unseen attacker
    583  1.10  christos  * 	280		fell into the dreadful sleep
    584  1.10  christos  * 	281		killed by an exploding chest
    585  1.10  christos  * 	282		killed by a missing maze data file
    586  1.10  christos  * 	283		killed by a sphere of annihilation
    587  1.10  christos  * 	284		died a post mortem death
    588  1.10  christos  * 	285		malloc() failure
    589  1.10  christos  * 	300		quick quit -- don't put on scoreboard
    590   1.1       cgd  */
    591   1.1       cgd 
    592  1.10  christos static int      scorerror;
    593  1.10  christos void
    594   1.1       cgd died(x)
    595  1.10  christos 	int             x;
    596  1.10  christos {
    597  1.10  christos 	int    f, win;
    598  1.15  dholland 	char            ch;
    599  1.15  dholland 	const char     *mod;
    600  1.10  christos 	time_t          zzz;
    601  1.10  christos 	if (c[LIFEPROT] > 0) {	/* if life protection */
    602  1.10  christos 		switch ((x > 0) ? x : -x) {
    603  1.10  christos 		case 256:
    604  1.10  christos 		case 257:
    605  1.10  christos 		case 262:
    606  1.10  christos 		case 263:
    607  1.10  christos 		case 265:
    608  1.10  christos 		case 266:
    609  1.10  christos 		case 267:
    610  1.10  christos 		case 268:
    611  1.10  christos 		case 269:
    612  1.10  christos 		case 271:
    613  1.10  christos 		case 282:
    614  1.10  christos 		case 284:
    615  1.10  christos 		case 285:
    616  1.10  christos 		case 300:
    617  1.10  christos 			goto invalid;	/* can't be saved */
    618  1.10  christos 		};
    619  1.10  christos 		--c[LIFEPROT];
    620  1.10  christos 		c[HP] = 1;
    621  1.10  christos 		--c[CONSTITUTION];
    622  1.10  christos 		cursors();
    623  1.10  christos 		lprcat("\nYou feel wiiieeeeerrrrrd all over! ");
    624  1.10  christos 		beep();
    625  1.10  christos 		lflush();
    626  1.10  christos 		sleep(4);
    627  1.10  christos 		return;		/* only case where died() returns */
    628  1.10  christos 	}
    629   1.1       cgd invalid:
    630  1.10  christos 	clearvt100();
    631  1.10  christos 	lflush();
    632  1.10  christos 	f = 0;
    633  1.10  christos 	if (ckpflag)
    634  1.10  christos 		unlink(ckpfile);/* remove checkpoint file if used */
    635  1.10  christos 	if (x < 0) {
    636  1.10  christos 		f++;
    637  1.10  christos 		x = -x;
    638  1.10  christos 	}			/* if we are not to display the scores */
    639  1.10  christos 	if ((x == 300) || (x == 257))
    640  1.10  christos 		exit(0);		/* for quick exit or saved game */
    641  1.10  christos 	if (x == 263)
    642  1.10  christos 		win = 1;
    643  1.10  christos 	else
    644  1.10  christos 		win = 0;
    645  1.10  christos 	c[GOLD] += c[BANKACCOUNT];
    646  1.10  christos 	c[BANKACCOUNT] = 0;
    647  1.10  christos 	/* now enter the player at the end of the scoreboard */
    648   1.1       cgd 	newscore(c[GOLD], logname, x, win);
    649  1.10  christos 	diedsub(x);		/* print out the score line */
    650  1.10  christos 	lflush();
    651   1.1       cgd 
    652   1.1       cgd 	set_score_output();
    653  1.10  christos 	if ((wizard == 0) && (c[GOLD] > 0)) {	/* wizards can't score		 */
    654   1.1       cgd #ifndef NOLOG
    655  1.16  dholland 		if (gid != egid)
    656  1.16  dholland 			setegid(egid);
    657  1.10  christos 		if (lappend(logfile) < 0) {	/* append to file */
    658  1.10  christos 			if (lcreat(logfile) < 0) {	/* and can't create new
    659  1.10  christos 							 * log file */
    660  1.10  christos 				lcreat((char *) 0);
    661   1.1       cgd 				lprcat("\nCan't open record file:  I can't post your score.\n");
    662  1.10  christos 				sncbr();
    663  1.10  christos 				resetscroll();
    664  1.10  christos 				lflush();
    665  1.10  christos 				exit(0);
    666  1.10  christos 			}
    667  1.16  dholland 			if (gid != egid)
    668  1.16  dholland 				setegid(egid);
    669  1.10  christos 			chmod(logfile, 0660);
    670  1.16  dholland 			if (gid != egid)
    671  1.16  dholland 				setegid(gid);
    672  1.13     mouse 		}
    673  1.16  dholland 		if (gid != egid)
    674  1.16  dholland 			setegid(gid);
    675  1.10  christos 		strcpy(logg.who, loginname);
    676  1.10  christos 		logg.score = c[GOLD];
    677  1.10  christos 		logg.diff = c[HARDGAME];
    678  1.10  christos 		if (x < 256) {
    679   1.1       cgd 			ch = *monster[x].name;
    680  1.10  christos 			if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
    681  1.10  christos 				mod = "an";
    682  1.10  christos 			else
    683  1.10  christos 				mod = "a";
    684  1.11  christos 			snprintf(logg.what, sizeof(logg.what),
    685  1.11  christos 			    "killed by %s %s", mod, monster[x].name);
    686  1.10  christos 		} else
    687  1.11  christos 			snprintf(logg.what, sizeof(logg.what),
    688  1.11  christos 			    "%s", whydead[x - 256]);
    689  1.10  christos 		logg.cavelev = level;
    690  1.12       wiz 		time(&zzz);	/* get CPU time -- write out score info */
    691  1.10  christos 		logg.diedtime = zzz;
    692   1.1       cgd #ifdef EXTRA
    693  1.12       wiz 		times(&cputime);/* get CPU time -- write out score info */
    694  1.10  christos 		logg.cputime = i = (cputime.tms_utime + cputime.tms_stime) / 60 + c[CPUTIME];
    695  1.10  christos 		logg.lev = c[LEVEL];
    696  1.10  christos 		logg.ac = c[AC];
    697  1.10  christos 		logg.hpmax = c[HPMAX];
    698  1.10  christos 		logg.hp = c[HP];
    699  1.10  christos 		logg.elapsedtime = (zzz - initialtime + 59) / 60;
    700  1.10  christos 		logg.usage = (10000 * i) / (zzz - initialtime);
    701  1.10  christos 		logg.bytin = c[BYTESIN];
    702  1.10  christos 		logg.bytout = c[BYTESOUT];
    703  1.10  christos 		logg.moves = c[MOVESMADE];
    704  1.10  christos 		logg.spused = c[SPELLSCAST];
    705  1.10  christos 		logg.killed = c[MONSTKILLED];
    706   1.1       cgd #endif
    707  1.10  christos 		lwrite((char *) &logg, sizeof(struct log_fmt));
    708  1.10  christos 		lwclose();
    709  1.10  christos #endif	/* NOLOG */
    710  1.10  christos 
    711  1.10  christos 		/*
    712  1.10  christos 		 * now for the scoreboard maintenance -- not for a suspended
    713  1.10  christos 		 * game
    714  1.10  christos 		 */
    715  1.10  christos 		if (x != 257) {
    716  1.13     mouse 			if (sortboard()) {
    717  1.13     mouse 				set_score_output();
    718  1.10  christos 				scorerror = writeboard();
    719  1.13     mouse 			}
    720  1.10  christos 		}
    721  1.10  christos 	}
    722  1.10  christos 	if ((x == 256) || (x == 257) || (f != 0))
    723  1.10  christos 		exit(0);
    724  1.10  christos 	if (scorerror == 0)
    725  1.10  christos 		showscores();	/* if we updated the scoreboard */
    726  1.10  christos 	if (x == 263)
    727  1.10  christos 		mailbill();
    728  1.10  christos 	exit(0);
    729  1.10  christos }
    730   1.1       cgd 
    731   1.1       cgd /*
    732  1.10  christos  * diedsub(x) Subroutine to print out the line showing the player when he is killed
    733  1.10  christos  * 	int x;
    734   1.1       cgd  */
    735  1.10  christos void
    736  1.15  dholland diedsub(int x)
    737  1.10  christos {
    738  1.15  dholland 	char   ch;
    739  1.15  dholland 	const char *mod;
    740  1.15  dholland 
    741  1.14  dholland 	lprintf("Score: %ld, Diff: %ld,  %s ", (long) c[GOLD], (long) c[HARDGAME], logname);
    742  1.10  christos 	if (x < 256) {
    743   1.1       cgd 		ch = *monster[x].name;
    744  1.10  christos 		if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
    745  1.10  christos 			mod = "an";
    746  1.10  christos 		else
    747  1.10  christos 			mod = "a";
    748  1.10  christos 		lprintf("killed by %s %s", mod, monster[x].name);
    749  1.10  christos 	} else
    750  1.10  christos 		lprintf("%s", whydead[x - 256]);
    751  1.10  christos 	if (x != 263)
    752  1.10  christos 		lprintf(" on %s\n", levelname[level]);
    753  1.10  christos 	else
    754  1.10  christos 		lprc('\n');
    755  1.10  christos }
    756   1.1       cgd 
    757   1.1       cgd /*
    758  1.10  christos  * diedlog() 	Subroutine to read a log file and print it out in ascii format
    759   1.1       cgd  */
    760  1.10  christos void
    761   1.1       cgd diedlog()
    762  1.10  christos {
    763  1.10  christos 	int    n;
    764  1.10  christos 	char  *p;
    765  1.10  christos 	struct stat     stbuf;
    766  1.10  christos 	lcreat((char *) 0);
    767  1.10  christos 	if (lopen(logfile) < 0) {
    768  1.10  christos 		lprintf("Can't locate log file <%s>\n", logfile);
    769   1.1       cgd 		return;
    770  1.10  christos 	}
    771  1.15  dholland 	if (fstat(io_infd, &stbuf) < 0) {
    772  1.10  christos 		lprintf("Can't  stat log file <%s>\n", logfile);
    773   1.1       cgd 		return;
    774  1.10  christos 	}
    775  1.10  christos 	for (n = stbuf.st_size / sizeof(struct log_fmt); n > 0; --n) {
    776  1.10  christos 		lrfill((char *) &logg, sizeof(struct log_fmt));
    777  1.10  christos 		p = ctime(&logg.diedtime);
    778  1.10  christos 		p[16] = '\n';
    779  1.10  christos 		p[17] = 0;
    780  1.14  dholland 		lprintf("Score: %ld, Diff: %ld,  %s %s on %ld at %s", (long) (logg.score), (long) (logg.diff), logg.who, logg.what, (long) (logg.cavelev), p + 4);
    781   1.1       cgd #ifdef EXTRA
    782  1.10  christos 		if (logg.moves <= 0)
    783  1.10  christos 			logg.moves = 1;
    784  1.15  dholland 		lprintf("  Experience Level: %ld,  AC: %ld,  HP: %ld/%ld,  Elapsed Time: %ld minutes\n", (long) (logg.lev), (long) (logg.ac), (long) (logg.hp), (long) (logg.hpmax), (long) (logg.elapsedtime));
    785  1.15  dholland 		lprintf("  CPU time used: %ld seconds,  Machine usage: %ld.%02ld%%\n", (long) (logg.cputime), (long) (logg.usage / 100), (long) (logg.usage % 100));
    786  1.15  dholland 		lprintf("  BYTES in: %ld, out: %ld, moves: %ld, deaths: %ld, spells cast: %ld\n", (long) (logg.bytin), (long) (logg.bytout), (long) (logg.moves), (long) (logg.killed), (long) (logg.spused));
    787  1.15  dholland 		lprintf("  out bytes per move: %ld,  time per move: %ld ms\n", (long) (logg.bytout / logg.moves), (long) ((logg.cputime * 1000) / logg.moves));
    788   1.1       cgd #endif
    789   1.1       cgd 	}
    790  1.10  christos 	lflush();
    791  1.10  christos 	lrclose();
    792  1.10  christos 	return;
    793  1.10  christos }
    794   1.1       cgd 
    795   1.1       cgd #ifndef UIDSCORE
    796   1.1       cgd /*
    797  1.10  christos  * getplid(name)		Function to get players id # from id file
    798   1.1       cgd  *
    799  1.10  christos  * Enter with the name of the players character in name.
    800  1.10  christos  * Returns the id # of the players character, or -1 if failure.
    801  1.10  christos  * This routine will try to find the name in the id file, if its not there,
    802  1.10  christos  * it will try to make a new entry in the file.  Only returns -1 if can't
    803  1.10  christos  * find him in the file, and can't make a new entry in the file.
    804  1.10  christos  * Format of playerids file:
    805  1.10  christos  * 		Id # in ascii     \n     character name     \n
    806   1.1       cgd  */
    807  1.10  christos static int      havepid = -1;	/* playerid # if previously done */
    808  1.10  christos int
    809   1.1       cgd getplid(nam)
    810  1.10  christos 	char           *nam;
    811  1.10  christos {
    812  1.10  christos 	int             fd7, high = 999, no;
    813  1.10  christos 	char  *p, *p2;
    814  1.10  christos 	char            name[80];
    815  1.10  christos 	if (havepid != -1)
    816  1.10  christos 		return (havepid);	/* already did it */
    817  1.10  christos 	lflush();		/* flush any pending I/O */
    818  1.11  christos 	snprintf(name, sizeof(name), "%s\n", nam);/* append a \n to name */
    819  1.10  christos 	if (lopen(playerids) < 0) {	/* no file, make it */
    820  1.17  dholland 		if ((fd7 = creat(playerids, 0664)) < 0)
    821  1.10  christos 			return (-1);	/* can't make it */
    822  1.10  christos 		close(fd7);
    823  1.10  christos 		goto addone;	/* now append new playerid record to file */
    824  1.10  christos 	}
    825  1.10  christos 	for (;;) {		/* now search for the name in the player id
    826  1.10  christos 				 * file */
    827  1.10  christos 		p = lgetl();
    828  1.10  christos 		if (p == NULL)
    829  1.10  christos 			break;	/* EOF? */
    830   1.1       cgd 		no = atoi(p);	/* the id # */
    831  1.10  christos 		p2 = lgetl();
    832  1.10  christos 		if (p2 == NULL)
    833  1.10  christos 			break;	/* EOF? */
    834  1.10  christos 		if (no > high)
    835  1.10  christos 			high = no;	/* accumulate highest id # */
    836  1.10  christos 		if (strcmp(p2, name) == 0) {	/* we found him */
    837  1.10  christos 			return (no);	/* his id number */
    838   1.1       cgd 		}
    839  1.10  christos 	}
    840   1.1       cgd 	lrclose();
    841   1.1       cgd 	/* if we get here, we didn't find him in the file -- put him there */
    842   1.1       cgd addone:
    843  1.10  christos 	if (lappend(playerids) < 0)
    844  1.10  christos 		return (-1);	/* can't open file for append */
    845  1.15  dholland 	lprintf("%ld\n%s", (long) ++high, name);	/* new id # and name */
    846   1.1       cgd 	lwclose();
    847  1.10  christos 	lcreat((char *) 0);	/* re-open terminal channel */
    848  1.10  christos 	return (high);
    849  1.10  christos }
    850  1.10  christos #endif	/* UIDSCORE */
    851