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