Initial import from FreeBSD RELENG_4:
[games.git] / games / phantasia / gamesupport.c
1 /*
2  * gamesupport.c - auxiliary routines for support of Phantasia
3  *
4  * $FreeBSD: src/games/phantasia/gamesupport.c,v 1.6 1999/11/16 02:57:33 billf Exp $
5  */
6
7 #include <string.h>
8 #include "include.h"
9
10 /************************************************************************
11 /
12 / FUNCTION NAME: changestats()
13 /
14 / FUNCTION: examine/change statistics for a player
15 /
16 / AUTHOR: E. A. Estes, 12/4/85
17 /
18 / ARGUMENTS:
19 /       bool ingameflag - set if called while playing game (Wizard only)
20 /
21 / RETURN VALUE: none
22 /
23 / MODULES CALLED: freerecord(), writerecord(), descrstatus(), truncstring(),
24 /       time(), more(), wmove(), wclear(), strcmp(), printw(), strcpy(),
25 /       infloat(), waddstr(), cleanup(), findname(), userlist(), mvprintw(),
26 /       localtime(), getanswer(), descrtype(), getstring()
27 /
28 / GLOBAL INPUTS: LINES, *Login, Other, Wizard, Player, *stdscr, Databuf[],
29 /       Fileloc
30 /
31 / GLOBAL OUTPUTS: Echo
32 /
33 / DESCRIPTION:
34 /       Prompt for player name to examine/change.
35 /       If the name is NULL, print a list of all players.
36 /       If we are called from within the game, check for the
37 /       desired name being the same as the current player's name.
38 /       Only the 'Wizard' may alter players.
39 /       Items are changed only if a non-zero value is specified.
40 /       To change an item to 0, use 0.1; it will be truncated later.
41 /
42 /       Players may alter their names and passwords, if the following
43 /       are true:
44 /           - current login matches the character's logins
45 /           - the password is known
46 /           - the player is not in the middle of the game (ingameflag == FALSE)
47 /
48 /       The last condition is imposed for two reasons:
49 /           - the game could possibly get a bit hectic if a player were
50 /             continually changing his/her name
51 /           - another player structure would be necessary to check for names
52 /             already in use
53 /
54 *************************************************************************/
55
56 changestats(ingameflag)
57 bool    ingameflag;
58 {
59 static char     flag[2] = /* for printing values of bools */
60         {'F', 'T'};
61 struct player   *playerp;/* pointer to structure to alter */
62 char    *prompt;        /* pointer to prompt string */
63 int     c;                      /* input */
64 int     today;                  /* day of year of today */
65 int     temp;                   /* temporary variable */
66 long    loc;                    /* location in player file */
67 time_t  now;                    /* time now */
68 double  dtemp;                  /* temporary variable */
69 bool    *bptr;                  /* pointer to bool item to change */
70 double  *dptr;                  /* pointer to double item to change */
71 short   *sptr;                  /* pointer to short item to change */
72
73     clear();
74
75     for (;;)
76         /* get name of player to examine/alter */
77         {
78         mvaddstr(5, 0, "Which character do you want to look at ? ");
79         getstring(Databuf, SZ_DATABUF);
80         truncstring(Databuf);
81
82         if (Databuf[0] == '\0')
83             userlist(ingameflag);
84         else
85             break;
86         }
87
88     loc = -1L;
89
90     if (!ingameflag)
91         /* use 'Player' structure */
92         playerp = &Player;
93     else if (strcmp(Databuf, Player.p_name) == 0)
94         /* alter/examine current player */
95         {
96         playerp = &Player;
97         loc = Fileloc;
98         }
99     else
100         /* use 'Other' structure */
101         playerp = &Other;
102
103     /* find player on file */
104     if (loc < 0L && (loc = findname(Databuf, playerp)) < 0L)
105         /* didn't find player */
106         {
107         clear();
108         mvaddstr(11, 0, "Not found.");
109         return;
110         }
111
112     time(&now);
113     today = localtime(&now)->tm_yday;
114
115     clear();
116
117     for (;;)
118         /* print player structure, and prompt for action */
119         {
120         mvprintw(0, 0,"A:Name         %s\n", playerp->p_name);
121
122         if (Wizard)
123             printw("B:Password     %s\n", playerp->p_password);
124         else
125             addstr("B:Password     XXXXXXXX\n");
126
127         printw(" :Login        %s\n", playerp->p_login);
128
129         printw("C:Experience   %.0f\n", playerp->p_experience);
130         printw("D:Level        %.0f\n", playerp->p_level);
131         printw("E:Strength     %.0f\n", playerp->p_strength);
132         printw("F:Sword        %.0f\n", playerp->p_sword);
133         printw(" :Might        %.0f\n", playerp->p_might);
134         printw("G:Energy       %.0f\n", playerp->p_energy);
135         printw("H:Max-Energy   %.0f\n", playerp->p_maxenergy);
136         printw("I:Shield       %.0f\n", playerp->p_shield);
137         printw("J:Quickness    %.0f\n", playerp->p_quickness);
138         printw("K:Quicksilver  %.0f\n", playerp->p_quksilver);
139         printw(" :Speed        %.0f\n", playerp->p_speed);
140         printw("L:Magic Level  %.0f\n", playerp->p_magiclvl);
141         printw("M:Mana         %.0f\n", playerp->p_mana);
142         printw("N:Brains       %.0f\n", playerp->p_brains);
143
144         if (Wizard || playerp->p_specialtype != SC_VALAR)
145             mvaddstr(0, 40, descrstatus(playerp));
146
147         mvprintw(1, 40, "O:Poison       %0.3f\n", playerp->p_poison);
148         mvprintw(2, 40, "P:Gold         %.0f\n", playerp->p_gold);
149         mvprintw(3, 40, "Q:Gem          %.0f\n", playerp->p_gems);
150         mvprintw(4, 40, "R:Sin          %0.3f\n", playerp->p_sin);
151         if (Wizard)
152             {
153             mvprintw(5, 40, "S:X-coord      %.0f\n", playerp->p_x);
154             mvprintw(6, 40, "T:Y-coord      %.0f\n", playerp->p_y);
155             }
156         else
157             {
158             mvaddstr(5, 40, "S:X-coord      ?\n");
159             mvaddstr(6, 40, "T:Y-coord      ?\n");
160             }
161
162         mvprintw(7, 40, "U:Age          %ld\n", playerp->p_age);
163         mvprintw(8, 40, "V:Degenerated  %d\n", playerp->p_degenerated);
164
165         mvprintw(9, 40, "W:Type         %d (%s)\n",
166             playerp->p_type, descrtype(playerp, FALSE) + 1);
167         mvprintw(10, 40, "X:Special Type %d\n", playerp->p_specialtype);
168         mvprintw(11, 40, "Y:Lives        %d\n", playerp->p_lives);
169         mvprintw(12, 40, "Z:Crowns       %d\n", playerp->p_crowns);
170         mvprintw(13, 40, "0:Charms       %d\n", playerp->p_charms);
171         mvprintw(14, 40, "1:Amulets      %d\n", playerp->p_amulets);
172         mvprintw(15, 40, "2:Holy Water   %d\n", playerp->p_holywater);
173
174         temp = today - playerp->p_lastused;
175         if (temp < 0)
176             /* last year */
177             temp += 365;
178         mvprintw(16, 40, "3:Lastused     %d  (%d)\n", playerp->p_lastused,  temp);
179
180         mvprintw(18, 8, "4:Palantir %c  5:Blessing %c  6:Virgin %c  7:Blind %c",
181             flag[playerp->p_palantir],
182             flag[playerp->p_blessing],
183             flag[playerp->p_virgin],
184             flag[playerp->p_blindness]);
185
186         if (!Wizard)
187             mvprintw(19, 8, "8:Ring    %c",
188                 flag[playerp->p_ring.ring_type != R_NONE]);
189         else
190             mvprintw(19, 8, "8:Ring    %d  9:Duration %d",
191                 playerp->p_ring.ring_type, playerp->p_ring.ring_duration);
192
193         if (!Wizard
194             /* not wizard */
195             && (ingameflag || strcmp(Login, playerp->p_login) != 0))
196             /* in game or not examining own character */
197             {
198             if (ingameflag)
199                 {
200                 more(LINES - 1);
201                 clear();
202                 return;
203                 }
204             else
205                 cleanup(TRUE);
206                 /*NOTREACHED*/
207             }
208
209         mvaddstr(20, 0, "!:Quit       ?:Delete");
210         mvaddstr(21, 0, "What would you like to change ? ");
211
212         if (Wizard)
213             c = getanswer(" ", TRUE);
214         else
215             /* examining own player; allow to change name and password */
216             c = getanswer("!BA", FALSE);
217
218         switch (c)
219             {
220             case 'A':   /* change name */
221             case 'B':   /* change password */
222                 if (!Wizard)
223                     /* prompt for password */
224                     {
225                     mvaddstr(23, 0, "Password ? ");
226                     Echo = FALSE;
227                     getstring(Databuf, 9);
228                     Echo = TRUE;
229                     if (strcmp(Databuf, playerp->p_password) != 0)
230                         continue;
231                     }
232
233                 if (c == 'A')
234                     /* get new name */
235                     {
236                     mvaddstr(23, 0, "New name: ");
237                     getstring(Databuf, SZ_NAME);
238                     truncstring(Databuf);
239                     if (Databuf[0] != '\0')
240                         if (Wizard || findname(Databuf, &Other) < 0L)
241                             strcpy(playerp->p_name, Databuf);
242                     }
243                 else
244                     /* get new password */
245                     {
246                     if (!Wizard)
247                         Echo = FALSE;
248
249                     do
250                         /* get two copies of new password until they match */
251                         {
252                         /* get first copy */
253                         mvaddstr(23, 0, "New password ? ");
254                         getstring(Databuf, SZ_PASSWORD);
255                         if (Databuf[0] == '\0')
256                             break;
257
258                         /* get second copy */
259                         mvaddstr(23, 0, "One more time ? ");
260                         getstring(playerp->p_password, SZ_PASSWORD);
261                         }
262                     while (strcmp(playerp->p_password, Databuf) != 0);
263
264                     Echo = TRUE;
265                     }
266
267                 continue;
268
269             case 'C':   /* change experience */
270                 prompt = "experience";
271                 dptr = &playerp->p_experience;
272                 goto DALTER;
273
274             case 'D':   /* change level */
275                 prompt = "level";
276                 dptr = &playerp->p_level;
277                 goto DALTER;
278
279             case 'E':   /* change strength */
280                 prompt = "strength";
281                 dptr = &playerp->p_strength;
282                 goto DALTER;
283
284             case 'F':   /* change swords */
285                 prompt = "sword";
286                 dptr = &playerp->p_sword;
287                 goto DALTER;
288
289             case 'G':   /* change energy */
290                 prompt = "energy";
291                 dptr = &playerp->p_energy;
292                 goto DALTER;
293
294             case 'H':   /* change maximum energy */
295                 prompt = "max energy";
296                 dptr = &playerp->p_maxenergy;
297                 goto DALTER;
298
299             case 'I':   /* change shields */
300                 prompt = "shield";
301                 dptr = &playerp->p_shield;
302                 goto DALTER;
303
304             case 'J':   /* change quickness */
305                 prompt = "quickness";
306                 dptr = &playerp->p_quickness;
307                 goto DALTER;
308
309             case 'K':   /* change quicksilver */
310                 prompt = "quicksilver";
311                 dptr = &playerp->p_quksilver;
312                 goto DALTER;
313
314             case 'L':   /* change magic */
315                 prompt = "magic level";
316                 dptr = &playerp->p_magiclvl;
317                 goto DALTER;
318
319             case 'M':   /* change mana */
320                 prompt = "mana";
321                 dptr = &playerp->p_mana;
322                 goto DALTER;
323
324             case 'N':   /* change brains */
325                 prompt = "brains";
326                 dptr = &playerp->p_brains;
327                 goto DALTER;
328
329             case 'O':   /* change poison */
330                 prompt = "poison";
331                 dptr = &playerp->p_poison;
332                 goto DALTER;
333
334             case 'P':   /* change gold */
335                 prompt = "gold";
336                 dptr = &playerp->p_gold;
337                 goto DALTER;
338
339             case 'Q':   /* change gems */
340                 prompt = "gems";
341                 dptr = &playerp->p_gems;
342                 goto DALTER;
343
344             case 'R':   /* change sin */
345                 prompt = "sin";
346                 dptr = &playerp->p_sin;
347                 goto DALTER;
348
349             case 'S':   /* change x coord */
350                 prompt = "x";
351                 dptr = &playerp->p_x;
352                 goto DALTER;
353
354             case 'T':   /* change y coord */
355                 prompt = "y";
356                 dptr = &playerp->p_y;
357                 goto DALTER;
358
359             case 'U':   /* change age */
360                 mvprintw(23, 0, "age = %ld; age = ", playerp->p_age);
361                 dtemp = infloat();
362                 if (dtemp != 0.0)
363                     playerp->p_age = (long) dtemp;
364                 continue;
365
366             case 'V':   /* change degen */
367                 mvprintw(23, 0, "degen = %d; degen = ", playerp->p_degenerated);
368                 dtemp = infloat();
369                 if (dtemp != 0.0)
370                     playerp->p_degenerated = (int) dtemp;
371                 continue;
372
373             case 'W':   /* change type */
374                 prompt = "type";
375                 sptr = &playerp->p_type;
376                 goto SALTER;
377
378             case 'X':   /* change special type */
379                 prompt = "special type";
380                 sptr = &playerp->p_specialtype;
381                 goto SALTER;
382
383             case 'Y':   /* change lives */
384                 prompt = "lives";
385                 sptr = &playerp->p_lives;
386                 goto SALTER;
387
388             case 'Z':   /* change crowns */
389                 prompt = "crowns";
390                 sptr = &playerp->p_crowns;
391                 goto SALTER;
392
393             case '0':   /* change charms */
394                 prompt = "charm";
395                 sptr = &playerp->p_charms;
396                 goto SALTER;
397
398             case '1':   /* change amulet */
399                 prompt = "amulet";
400                 sptr = &playerp->p_amulets;
401                 goto SALTER;
402
403             case '2':   /* change holy water */
404                 prompt = "holy water";
405                 sptr = &playerp->p_holywater;
406                 goto SALTER;
407
408             case '3':   /* change last-used */
409                 prompt = "last-used";
410                 sptr = &playerp->p_lastused;
411                 goto SALTER;
412
413             case '4':   /* change palantir */
414                 prompt = "palantir";
415                 bptr = &playerp->p_palantir;
416                 goto BALTER;
417
418             case '5':   /* change blessing */
419                 prompt = "blessing";
420                 bptr = &playerp->p_blessing;
421                 goto BALTER;
422
423             case '6':   /* change virgin */
424                 prompt = "virgin";
425                 bptr = &playerp->p_virgin;
426                 goto BALTER;
427
428             case '7':   /* change blindness */
429                 prompt = "blindness";
430                 bptr = &playerp->p_blindness;
431                 goto BALTER;
432
433             case '8':   /* change ring type */
434                 prompt = "ring-type";
435                 sptr = &playerp->p_ring.ring_type;
436                 goto SALTER;
437
438             case '9':   /* change ring duration */
439                 prompt = "ring-duration";
440                 sptr = &playerp->p_ring.ring_duration;
441                 goto SALTER;
442
443             case '!':   /* quit, update */
444                 if (Wizard &&
445                     (!ingameflag || playerp != &Player))
446                     /* turn off status if not modifying self */
447                     {
448                     playerp->p_status = S_OFF;
449                     playerp->p_tampered = T_OFF;
450                     }
451
452                 writerecord(playerp, loc);
453                 clear();
454                 return;
455
456             case '?':   /* delete player */
457                 if (ingameflag && playerp == &Player)
458                     /* cannot delete self */
459                     continue;
460
461                 freerecord(playerp, loc);
462                 clear();
463                 return;
464
465             default:
466                 continue;
467             }
468 DALTER:
469         mvprintw(23, 0, "%s = %f; %s = ", prompt, *dptr, prompt);
470         dtemp = infloat();
471         if (dtemp != 0.0)
472             *dptr = dtemp;
473         continue;
474
475 SALTER:
476         mvprintw(23, 0, "%s = %d; %s = ", prompt, *sptr, prompt);
477         dtemp = infloat();
478         if (dtemp != 0.0)
479             *sptr = (short) dtemp;
480         continue;
481
482 BALTER:
483         mvprintw(23, 0, "%s = %c; %s = ", prompt, flag[*bptr], prompt);
484         c = getanswer("\nTF", TRUE);
485         if (c == 'T')
486             *bptr = TRUE;
487         else if (c == 'F')
488             *bptr = FALSE;
489         continue;
490         }
491 }
492 /*\f*/
493 /************************************************************************
494 /
495 / FUNCTION NAME: monstlist()
496 /
497 / FUNCTION: print a monster listing
498 /
499 / AUTHOR: E. A. Estes, 2/27/86
500 /
501 / ARGUMENTS: none
502 /
503 / RETURN VALUE: none
504 /
505 / MODULES CALLED: puts(), fread(), fseek(), printf()
506 /
507 / GLOBAL INPUTS: Curmonster, *Monstfp
508 /
509 / GLOBAL OUTPUTS: none
510 /
511 / DESCRIPTION:
512 /       Read monster file, and print a monster listing on standard output.
513 /
514 *************************************************************************/
515
516 monstlist()
517 {
518 int     count = 0;              /* count in file */
519
520     puts(" #)  Name                 Str  Brain  Quick  Energy  Exper  Treas  Type  Flock%\n");
521     fseek(Monstfp, 0L, 0);
522     while (fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp) == 1)
523         printf("%2d)  %-20.20s%4.0f   %4.0f     %2.0f   %5.0f  %5.0f     %2d    %2d     %3.0f\n", count++,
524             Curmonster.m_name, Curmonster.m_strength, Curmonster.m_brains,
525             Curmonster.m_speed, Curmonster.m_energy, Curmonster.m_experience,
526             Curmonster.m_treasuretype, Curmonster.m_type, Curmonster.m_flock);
527 }
528 /*\f*/
529 /************************************************************************
530 /
531 / FUNCTION NAME: scorelist()
532 /
533 / FUNCTION: print player score board
534 /
535 / AUTHOR: E. A. Estes, 12/4/85
536 /
537 / ARGUMENTS: none
538 /
539 / RETURN VALUE: none
540 /
541 / MODULES CALLED: fread(), fopen(), printf(), fclose()
542 /
543 / GLOBAL INPUTS:
544 /
545 / GLOBAL OUTPUTS: none
546 /
547 / DESCRIPTION:
548 /       Read the scoreboard file and print the contents.
549 /
550 *************************************************************************/
551
552 scorelist()
553 {
554 struct  scoreboard      sbuf;   /* for reading entries */
555 FILE    *fp;            /* to open the file */
556
557     if ((fp = fopen(_PATH_SCORE, "r")) != NULL)
558         {
559         while (fread((char *) &sbuf, SZ_SCORESTRUCT, 1, fp) == 1)
560             printf("%-20s   (%-9s)  Level: %6.0f  Type: %s\n",
561                 sbuf.sb_name, sbuf.sb_login, sbuf.sb_level, sbuf.sb_type);
562         fclose(fp);
563         }
564 }
565 /*\f*/
566 /************************************************************************
567 /
568 / FUNCTION NAME: activelist()
569 /
570 / FUNCTION: print list of active players to standard output
571 /
572 / AUTHOR: E. A. Estes, 3/7/86
573 /
574 / ARGUMENTS: none
575 /
576 / RETURN VALUE: none
577 /
578 / MODULES CALLED: descrstatus(), fread(), fseek(), printf(), descrtype()
579 /
580 / GLOBAL INPUTS: Other, *Playersfp
581 /
582 / GLOBAL OUTPUTS: none
583 /
584 / DESCRIPTION:
585 /       Read player file, and print list of active records to standard output.
586 /
587 *************************************************************************/
588
589 activelist()
590 {
591     fseek(Playersfp, 0L, 0);
592     printf("Current characters on file are:\n\n");
593
594     while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
595         if (Other.p_status != S_NOTUSED)
596             printf("%-20s   (%-9s)  Level: %6.0f  %s  (%s)\n",
597                 Other.p_name, Other.p_login, Other.p_level,
598                 descrtype(&Other, FALSE), descrstatus(&Other));
599
600 }
601 /*\f*/
602 /************************************************************************
603 /
604 / FUNCTION NAME: purgeoldplayers()
605 /
606 / FUNCTION: purge inactive players from player file
607 /
608 / AUTHOR: E. A. Estes, 12/4/85
609 /
610 / ARGUMENTS: none
611 /
612 / RETURN VALUE: none
613 /
614 / MODULES CALLED: freerecord(), time(), fread(), fseek(), localtime()
615 /
616 / GLOBAL INPUTS: Other, *Playersfp
617 /
618 / GLOBAL OUTPUTS: none
619 /
620 / DESCRIPTION:
621 /       Delete characters which have not been used with the last
622 /       three weeks.
623 /
624 *************************************************************************/
625
626 purgeoldplayers()
627 {
628 int     today;          /* day of year for today */
629 int     daysold;        /* how many days since the character has been used */
630 time_t  ltime;          /* time in seconds */
631 long    loc = 0L;       /* location in file */
632
633     time(&ltime);
634     today = localtime(&ltime)->tm_yday;
635
636     for (;;)
637         {
638         fseek(Playersfp, loc, 0);
639         if (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) != 1)
640             break;
641
642         daysold = today - Other.p_lastused;
643         if (daysold < 0)
644             daysold += 365;
645
646         if (daysold > N_DAYSOLD)
647             /* player hasn't been used in a while; delete */
648             freerecord(&Other, loc);
649
650         loc += SZ_PLAYERSTRUCT;
651         }
652 }
653 /*\f*/
654 /************************************************************************
655 /
656 / FUNCTION NAME: enterscore()
657 /
658 / FUNCTION: enter player into scoreboard
659 /
660 / AUTHOR: E. A. Estes, 12/4/85
661 /
662 / ARGUMENTS: none
663 /
664 / RETURN VALUE: none
665 /
666 / MODULES CALLED: fread(), fseek(), fopen(), error(), strcmp(), fclose(),
667 /       strcpy(), fwrite(), descrtype()
668 /
669 / GLOBAL INPUTS: Player
670 /
671 / GLOBAL OUTPUTS: none
672 /
673 / DESCRIPTION:
674 /       The scoreboard keeps track of the highest character on a
675 /       per-login basis.
676 /       Search the scoreboard for an entry for the current login,
677 /       if an entry is found, and it is lower than the current player,
678 /       replace it, otherwise create an entry.
679 /
680 *************************************************************************/
681
682 enterscore()
683 {
684 struct  scoreboard sbuf;                /* buffer to read in scoreboard entries */
685 FILE    *fp;                            /* to open scoreboard file */
686 long    loc = 0L;                       /* location in scoreboard file */
687 bool    found = FALSE;                  /* set if we found an entry for this login */
688
689     if ((fp = fopen(_PATH_SCORE, "r+")) != NULL)
690         {
691         while (fread((char *) &sbuf, SZ_SCORESTRUCT, 1, fp) == 1)
692             if (strcmp(Player.p_login, sbuf.sb_login) == 0)
693                 {
694                 found = TRUE;
695                 break;
696                 }
697             else
698                 loc += SZ_SCORESTRUCT;
699         }
700     else
701         {
702         error(_PATH_SCORE);
703         /*NOTREACHED*/
704         }
705
706     /*
707      * At this point, 'loc' will either indicate a point beyond
708      * the end of file, or the place where the previous entry
709      * was found.
710      */
711
712     if ((!found) || Player.p_level > sbuf.sb_level)
713         /* put new entry in for this login */
714         {
715         strcpy(sbuf.sb_login, Player.p_login);
716         strcpy(sbuf.sb_name, Player.p_name);
717         sbuf.sb_level = Player.p_level;
718         strcpy(sbuf.sb_type, descrtype(&Player, TRUE));
719         }
720
721     /* update entry */
722     fseek(fp, loc, 0);
723     fwrite((char *) &sbuf, SZ_SCORESTRUCT, 1, fp);
724     fclose(fp);
725 }