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