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