Initial import from FreeBSD RELENG_4:
[dragonfly.git] / games / larn / scores.c
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