Generally use NULL instead of explicitly casting 0 to some pointer type.
[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  * $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