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