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