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