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