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