Make this compile with gcc40: rename variables so that they don't collide
[dragonfly.git] / games / phantasia / main.c
... / ...
CommitLineData
1/*
2 * Phantasia 3.3.2 -- Interterminal fantasy game
3 *
4 * Edward A. Estes
5 * AT&T, March 12, 1986
6 *
7 * $FreeBSD: src/games/phantasia/main.c,v 1.8 1999/11/16 02:57:34 billf Exp $
8 * $DragonFly: src/games/phantasia/main.c,v 1.2 2003/06/17 04:25:24 dillon Exp $
9 */
10
11/* DISCLAIMER:
12 *
13 * This game is distributed for free as is. It is not guaranteed to work
14 * in every conceivable environment. It is not even guaranteed to work
15 * in ANY environment.
16 *
17 * This game is distributed without notice of copyright, therefore it
18 * may be used in any manner the recipient sees fit. However, the
19 * author assumes no responsibility for maintaining or revising this
20 * game, in its original form, or any derivitives thereof.
21 *
22 * The author shall not be responsible for any loss, cost, or damage,
23 * including consequential damage, caused by reliance on this material.
24 *
25 * The author makes no warranties, express or implied, including warranties
26 * of merchantability or fitness for a particular purpose or use.
27 *
28 * AT&T is in no way connected with this game.
29 */
30
31#include <sys/types.h>
32#include <pwd.h>
33#include <string.h>
34
35/*
36 * The program allocates as much file space as it needs to store characters,
37 * so the possibility exists for the character file to grow without bound.
38 * The file is purged upon normal entry to try to avoid that problem.
39 * A similar problem exists for energy voids. To alleviate the problem here,
40 * the void file is cleared with every new king, and a limit is placed
41 * on the size of the energy void file.
42 */
43
44/*
45 * Put one line of text into the file 'motd' for announcements, etc.
46 */
47
48/*
49 * The scoreboard file is updated when someone dies, and keeps track
50 * of the highest character to date for that login.
51 * Being purged from the character file does not cause the scoreboard
52 * to be updated.
53 */
54
55/*
56 * All source files are set up for 'vi' with shiftwidth=4, tabstop=8.
57 */
58
59/*\f*/
60
61/*
62 * main.c Main routines for Phantasia
63 */
64
65#include "include.h"
66
67/***************************************************************************
68/ FUNCTION NAME: main()
69/
70/ FUNCTION: initialize state, and call main process
71/
72/ AUTHOR: E. A. Estes, 12/4/85
73/
74/ ARGUMENTS:
75/ int argc - argument count
76/ char **argv - argument vector
77/
78/ RETURN VALUE: none
79/
80/ MODULES CALLED: monstlist(), checkenemy(), activelist(),
81/ throneroom(), checkbattle(), readmessage(), changestats(), writerecord(),
82/ tradingpost(), adjuststats(), recallplayer(), displaystats(), checktampered(),
83/ fabs(), rollnewplayer(), time(), exit(), sqrt(), floor(), wmove(),
84/ signal(), strcat(), purgeoldplayers(), getuid(), isatty(), wclear(),
85/ strcpy(), system(), altercoordinates(), cleanup(), waddstr(), procmain(),
86/ playinit(), leavegame(), localtime(), getanswer(), neatstuff(), initialstate(),
87/ scorelist(), titlelist()
88/
89/ GLOBAL INPUTS: *Login, Throne, Wizard, Player, *stdscr, Changed, Databuf[],
90/ Fileloc, Stattable[]
91/
92/ GLOBAL OUTPUTS: Wizard, Player, Changed, Fileloc, Timeout, *Statptr
93/
94/ DESCRIPTION:
95/ Process arguments, initialize program, and loop forever processing
96/ player input.
97/
98****************************************************************************/
99
100main(argc, argv)
101int argc;
102char **argv;
103{
104bool noheader = FALSE; /* set if don't want header */
105bool headeronly = FALSE; /* set if only want header */
106bool examine = FALSE; /* set if examine a character */
107time_t seconds; /* for time of day */
108double dtemp; /* for temporary calculations */
109
110 initialstate(); /* init globals */
111
112 /* process arguments */
113 while (--argc && (*++argv)[0] == '-')
114 switch ((*argv)[1])
115 {
116 case 's': /* short */
117 noheader = TRUE;
118 break;
119
120 case 'H': /* Header */
121 headeronly = TRUE;
122 break;
123
124 case 'a': /* all users */
125 activelist();
126 cleanup(TRUE);
127 /*NOTREACHED*/
128
129 case 'p': /* purge old players */
130 purgeoldplayers();
131 cleanup(TRUE);
132 /*NOTREACHED*/
133
134 case 'S': /* set 'Wizard' */
135 Wizard = !getuid();
136 break;
137
138 case 'x': /* examine */
139 examine = TRUE;
140 break;
141
142 case 'm': /* monsters */
143 monstlist();
144 cleanup(TRUE);
145 /*NOTREACHED*/
146
147 case 'b': /* scoreboard */
148 scorelist();
149 cleanup(TRUE);
150 /*NOTREACHED*/
151 }
152
153 if (!isatty(0)) /* don't let non-tty's play */
154 cleanup(TRUE);
155 /*NOTREACHED*/
156
157 playinit(); /* set up to catch signals, init curses */
158
159 if (examine)
160 {
161 changestats(FALSE);
162 cleanup(TRUE);
163 /*NOTREACHED*/
164 }
165
166 if (!noheader)
167 {
168 titlelist();
169 purgeoldplayers(); /* clean up old characters */
170 }
171
172 if (headeronly)
173 cleanup(TRUE);
174 /*NOTREACHED*/
175
176 do
177 /* get the player structure filled */
178 {
179 Fileloc = -1L;
180
181 mvaddstr(22, 17, "Do you have a character to run [Q = Quit] ? ");
182
183 switch (getanswer("NYQ", FALSE))
184 {
185 case 'Y':
186 Fileloc = recallplayer();
187 break;
188
189 case 'Q':
190 cleanup(TRUE);
191 /*NOTREACHED*/
192
193 default:
194 Fileloc = rollnewplayer();
195 break;
196 }
197 clear();
198 }
199 while (Fileloc < 0L);
200
201 if (Player.p_level > 5.0)
202 /* low level players have long timeout */
203 Timeout = TRUE;
204
205 /* update some important player statistics */
206 strcpy(Player.p_login, Login);
207 time(&seconds);
208 Player.p_lastused = localtime(&seconds)->tm_yday;
209 Player.p_status = S_PLAYING;
210 writerecord(&Player, Fileloc);
211
212 Statptr = &Stattable[Player.p_type]; /* initialize pointer */
213
214 /* catch interrupts */
215#ifdef BSD41
216 sigset(SIGINT, interrupt);
217#endif
218#ifdef BSD42
219 signal(SIGINT, interrupt);
220#endif
221#ifdef SYS3
222 signal(SIGINT, interrupt);
223#endif
224#ifdef SYS5
225 signal(SIGINT, interrupt);
226#endif
227
228 altercoordinates(Player.p_x, Player.p_y, A_FORCED); /* set some flags */
229
230 clear();
231
232 for (;;)
233 /* loop forever, processing input */
234 {
235
236 adjuststats(); /* cleanup stats */
237
238 if (Throne && Player.p_crowns == 0 && Player.p_specialtype != SC_KING)
239 /* not allowed on throne -- move */
240 {
241 mvaddstr(5,0,"You're not allowed in the Lord's Chamber without a crown.\n");
242 altercoordinates(0.0, 0.0, A_NEAR);
243 }
244
245 checktampered(); /* check for energy voids, etc. */
246
247 if (Player.p_status != S_CLOAKED
248 /* not cloaked */
249 && (dtemp = fabs(Player.p_x)) == fabs(Player.p_y)
250 /* |x| = |y| */
251 && !Throne)
252 /* not on throne */
253 {
254 dtemp = sqrt(dtemp / 100.0);
255 if (floor(dtemp) == dtemp)
256 /* |x| / 100 == n*n; at a trading post */
257 {
258 tradingpost();
259 clear();
260 }
261 }
262
263 checkbattle(); /* check for player to player battle */
264 neatstuff(); /* gurus, medics, etc. */
265
266 if (Player.p_status == S_CLOAKED)
267 /* costs 3 mana per turn to be cloaked */
268 if (Player.p_mana > 3.0)
269 Player.p_mana -= 3.0;
270 else
271 /* ran out of mana, uncloak */
272 {
273 Player.p_status = S_PLAYING;
274 Changed = TRUE;
275 }
276
277 if (Player.p_status != S_PLAYING && Player.p_status != S_CLOAKED)
278 /* change status back to S_PLAYING */
279 {
280 Player.p_status = S_PLAYING;
281 Changed = TRUE;
282 }
283
284 if (Changed)
285 /* update file only if important stuff has changed */
286 {
287 writerecord(&Player, Fileloc);
288 Changed = FALSE;
289 continue;
290 }
291
292 readmessage(); /* read message, if any */
293
294 displaystats(); /* print statistics */
295
296 move(6, 0);
297
298 if (Throne)
299 /* maybe make king, print prompt, etc. */
300 throneroom();
301
302 /* print status line */
303 addstr("1:Move 2:Players 3:Talk 4:Stats 5:Quit ");
304 if (Player.p_level >= MEL_CLOAK && Player.p_magiclvl >= ML_CLOAK)
305 addstr("6:Cloak ");
306 if (Player.p_level >= MEL_TELEPORT && Player.p_magiclvl >= ML_TELEPORT)
307 addstr("7:Teleport ");
308 if (Player.p_specialtype >= SC_COUNCIL || Wizard)
309 addstr("8:Intervene ");
310
311 procmain(); /* process input */
312 }
313}
314/*\f*/
315/************************************************************************
316/
317/ FUNCTION NAME: initialstate()
318/
319/ FUNCTION: initialize some important global variable
320/
321/ AUTHOR: E. A. Estes, 12/4/85
322/
323/ ARGUMENTS: none
324/
325/ RETURN VALUE: none
326/
327/ MODULES CALLED: time(), fopen(), srandom(), error(), getuid(), getlogin(),
328/ getpwuid()
329/
330/ GLOBAL INPUTS:
331/
332/ GLOBAL OUTPUTS: *Energyvoidfp, Echo, Marsh, *Login, Users, Beyond,
333/ Throne, Wizard, Changed, Okcount, Timeout, Windows, *Monstfp, *Messagefp,
334/ *Playersfp
335/
336/ DESCRIPTION:
337/ Set global flags, and open files which remain open.
338/
339*************************************************************************/
340
341initialstate()
342{
343 Beyond = FALSE;
344 Marsh = FALSE;
345 Throne = FALSE;
346 Changed = FALSE;
347 Wizard = FALSE;
348 Timeout = FALSE;
349 Users = 0;
350 Windows = FALSE;
351 Echo = TRUE;
352
353 /* setup login name */
354 if ((Login = getlogin()) == NULL)
355 Login = getpwuid(getuid())->pw_name;
356
357 /* open some files */
358 if ((Playersfp = fopen(_PATH_PEOPLE, "r+")) == NULL)
359 error(_PATH_PEOPLE);
360 /*NOTREACHED*/
361
362 if ((Monstfp = fopen(_PATH_MONST, "r+")) == NULL)
363 error(_PATH_MONST);
364 /*NOTREACHED*/
365
366 if ((Messagefp = fopen(_PATH_MESS, "r")) == NULL)
367 error(_PATH_MESS);
368 /*NOTREACHED*/
369
370 if ((Energyvoidfp = fopen(_PATH_VOID, "r+")) == NULL)
371 error(_PATH_VOID);
372 /*NOTREACHED*/
373
374 srandomdev();
375}
376/*\f*/
377/************************************************************************
378/
379/ FUNCTION NAME: rollnewplayer()
380/
381/ FUNCTION: roll up a new character
382/
383/ AUTHOR: E. A. Estes, 12/4/85
384/
385/ ARGUMENTS: none
386/
387/ RETURN VALUE: none
388/
389/ MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(),
390/ wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw(),
391/ getanswer(), getstring()
392/
393/ GLOBAL INPUTS: Other, Wizard, Player, *stdscr, Databuf[]
394/
395/ GLOBAL OUTPUTS: Echo
396/
397/ DESCRIPTION:
398/ Prompt player, and roll up new character.
399/
400*************************************************************************/
401
402long
403rollnewplayer()
404{
405int chartype; /* character type */
406int ch; /* input */
407
408 initplayer(&Player); /* initialize player structure */
409
410 clear();
411 mvaddstr(4, 21, "Which type of character do you want:");
412 mvaddstr(8, 4, "1:Magic User 2:Fighter 3:Elf 4:Dwarf 5:Halfling 6:Experimento ");
413 if (Wizard) {
414 addstr("7:Super ? ");
415 chartype = getanswer("1234567", FALSE);
416 }
417 else {
418 addstr("? ");
419 chartype = getanswer("123456", FALSE);
420 }
421
422 do
423 {
424 genchar(chartype); /* roll up a character */
425
426 /* print out results */
427 mvprintw(12, 14,
428 "Strength : %2.0f Quickness: %2.0f Mana : %2.0f\n",
429 Player.p_strength, Player.p_quickness, Player.p_mana);
430 mvprintw(13, 14,
431 "Energy Level: %2.0f Brains : %2.0f Magic Level: %2.0f\n",
432 Player.p_energy, Player.p_brains, Player.p_magiclvl);
433
434 if (Player.p_type == C_EXPER || Player.p_type == C_SUPER)
435 break;
436
437 mvaddstr(14, 14, "Type '1' to keep >");
438 ch = getanswer(" ", TRUE);
439 }
440 while (ch != '1');
441
442 if (Player.p_type == C_EXPER || Player.p_type == C_SUPER)
443 /* get coordinates for experimento */
444 for (;;)
445 {
446 mvaddstr(16, 0, "Enter the X Y coordinates of your experimento ? ");
447 getstring(Databuf, SZ_DATABUF);
448 sscanf(Databuf, "%lf %lf", &Player.p_x, &Player.p_y);
449
450 if (fabs(Player.p_x) > D_EXPER || fabs(Player.p_y) > D_EXPER)
451 mvaddstr(17, 0, "Invalid coordinates. Try again.\n");
452 else
453 break;
454 }
455
456 for (;;)
457 /* name the new character */
458 {
459 mvprintw(18, 0,
460 "Give your character a name [up to %d characters] ? ", SZ_NAME - 1);
461 getstring(Player.p_name, SZ_NAME);
462 truncstring(Player.p_name); /* remove trailing blanks */
463
464 if (Player.p_name[0] == '\0')
465 /* no null names */
466 mvaddstr(19, 0, "Invalid name.");
467 else if (findname(Player.p_name, &Other) >= 0L)
468 /* cannot have duplicate names */
469 mvaddstr(19, 0, "Name already in use.");
470 else
471 /* name is acceptable */
472 break;
473
474 addstr(" Pick another.\n");
475 }
476
477 /* get a password for character */
478 Echo = FALSE;
479
480 do
481 {
482 mvaddstr(20, 0, "Give your character a password [up to 8 characters] ? ");
483 getstring(Player.p_password, SZ_PASSWORD);
484 mvaddstr(21, 0, "One more time to verify ? ");
485 getstring(Databuf, SZ_PASSWORD);
486 }
487 while (strcmp(Player.p_password, Databuf) != 0);
488
489 Echo = TRUE;
490
491 return(allocrecord());
492}
493/*\f*/
494/************************************************************************
495/
496/ FUNCTION NAME: procmain()
497/
498/ FUNCTION: process input from player
499/
500/ AUTHOR: E. A. Estes, 12/4/85
501/
502/ ARGUMENTS: none
503/
504/ RETURN VALUE: none
505/
506/ MODULES CALLED: dotampered(), changestats(), inputoption(), allstatslist(),
507/ fopen(), wmove(), drandom(), sscanf(), fclose(), altercoordinates(),
508/ waddstr(), fprintf(), distance(), userlist(), leavegame(), encounter(),
509/ getstring(), wclrtobot()
510/
511/ GLOBAL INPUTS: Circle, Illcmd[], Throne, Wizard, Player, *stdscr,
512/ Databuf[], Illmove[]
513/
514/ GLOBAL OUTPUTS: Player, Changed
515/
516/ DESCRIPTION:
517/ Process main menu options.
518/
519*************************************************************************/
520
521procmain()
522{
523int ch; /* input */
524double x; /* desired new x coordinate */
525double y; /* desired new y coordinate */
526double temp; /* for temporary calculations */
527FILE *fp; /* for opening files */
528int loop; /* a loop counter */
529bool hasmoved = FALSE; /* set if player has moved */
530
531 ch = inputoption();
532 mvaddstr(4, 0, "\n\n"); /* clear status area */
533
534 move(7, 0);
535 clrtobot(); /* clear data on bottom area of screen */
536
537 if (Player.p_specialtype == SC_VALAR && (ch == '1' || ch == '7'))
538 /* valar cannot move */
539 ch = ' ';
540
541 switch (ch)
542 {
543 case 'K': /* move up/north */
544 case 'N':
545 x = Player.p_x;
546 y = Player.p_y + MAXMOVE();
547 hasmoved = TRUE;
548 break;
549
550 case 'J': /* move down/south */
551 case 'S':
552 x = Player.p_x;
553 y = Player.p_y - MAXMOVE();
554 hasmoved = TRUE;
555 break;
556
557 case 'L': /* move right/east */
558 case 'E':
559 x = Player.p_x + MAXMOVE();
560 y = Player.p_y;
561 hasmoved = TRUE;
562 break;
563
564 case 'H': /* move left/west */
565 case 'W':
566 x = Player.p_x - MAXMOVE();
567 y = Player.p_y;
568 hasmoved = TRUE;
569 break;
570
571 default: /* rest */
572 Player.p_energy += (Player.p_maxenergy + Player.p_shield) / 15.0
573 + Player.p_level / 3.0 + 2.0;
574 Player.p_energy =
575 MIN(Player.p_energy, Player.p_maxenergy + Player.p_shield);
576
577 if (Player.p_status != S_CLOAKED)
578 /* cannot find mana if cloaked */
579 {
580 Player.p_mana += (Circle + Player.p_level) / 4.0;
581
582 if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne)
583 /* wandering monster */
584 encounter(-1);
585 }
586 break;
587
588 case 'X': /* change/examine a character */
589 changestats(TRUE);
590 break;
591
592 case '1': /* move */
593 for (loop = 3; loop; --loop)
594 {
595 mvaddstr(4, 0, "X Y Coordinates ? ");
596 getstring(Databuf, SZ_DATABUF);
597
598 if (sscanf(Databuf, "%lf %lf", &x, &y) != 2)
599 mvaddstr(5, 0, "Try again\n");
600 else if (distance(Player.p_x, x, Player.p_y, y) > MAXMOVE())
601 ILLMOVE();
602 else
603 {
604 hasmoved = TRUE;
605 break;
606 }
607 }
608 break;
609
610 case '2': /* players */
611 userlist(TRUE);
612 break;
613
614 case '3': /* message */
615 mvaddstr(4, 0, "Message ? ");
616 getstring(Databuf, SZ_DATABUF);
617 /* we open the file for writing to erase any data which is already there */
618 fp = fopen(_PATH_MESS, "w");
619 if (Databuf[0] != '\0')
620 fprintf(fp, "%s: %s", Player.p_name, Databuf);
621 fclose(fp);
622 break;
623
624 case '4': /* stats */
625 allstatslist();
626 break;
627
628 case '5': /* good-bye */
629 leavegame();
630 /*NOTREACHED*/
631
632 case '6': /* cloak */
633 if (Player.p_level < MEL_CLOAK || Player.p_magiclvl < ML_CLOAK)
634 ILLCMD();
635 else if (Player.p_status == S_CLOAKED)
636 Player.p_status = S_PLAYING;
637 else if (Player.p_mana < MM_CLOAK)
638 mvaddstr(5, 0, "No mana left.\n");
639 else
640 {
641 Changed = TRUE;
642 Player.p_mana -= MM_CLOAK;
643 Player.p_status = S_CLOAKED;
644 }
645 break;
646
647 case '7': /* teleport */
648 /*
649 * conditions for teleport
650 * - 20 per (level plus magic level)
651 * - OR council of the wise or valar or ex-valar
652 * - OR transport from throne
653 * transports from throne cost no mana
654 */
655 if (Player.p_level < MEL_TELEPORT || Player.p_magiclvl < ML_TELEPORT)
656 ILLCMD();
657 else
658 for (loop = 3; loop; --loop)
659 {
660 mvaddstr(4, 0, "X Y Coordinates ? ");
661 getstring(Databuf, SZ_DATABUF);
662
663 if (sscanf(Databuf, "%lf %lf", &x, &y) == 2)
664 {
665 temp = distance(Player.p_x, x, Player.p_y, y);
666 if (!Throne
667 /* can transport anywhere from throne */
668 && Player.p_specialtype <= SC_COUNCIL
669 /* council, valar can transport anywhere */
670 && temp > (Player.p_level + Player.p_magiclvl) * 20.0)
671 /* can only move 20 per exp. level + mag. level */
672 ILLMOVE();
673 else
674 {
675 temp = (temp / 75.0 + 1.0) * 20.0; /* mana used */
676
677 if (!Throne && temp > Player.p_mana)
678 mvaddstr(5, 0, "Not enough power for that distance.\n");
679 else
680 {
681 if (!Throne)
682 Player.p_mana -= temp;
683 hasmoved = TRUE;
684 break;
685 }
686 }
687 }
688 }
689 break;
690
691 case 'C':
692 case '9': /* monster */
693 if (Throne)
694 /* no monsters while on throne */
695 mvaddstr(5, 0, "No monsters in the chamber!\n");
696 else if (Player.p_specialtype != SC_VALAR)
697 /* the valar cannot call monsters */
698 {
699 Player.p_sin += 1e-6;
700 encounter(-1);
701 }
702 break;
703
704 case '0': /* decree */
705 if (Wizard || Player.p_specialtype == SC_KING && Throne)
706 /* kings must be on throne to decree */
707 dotampered();
708 else
709 ILLCMD();
710 break;
711
712 case '8': /* intervention */
713 if (Wizard || Player.p_specialtype >= SC_COUNCIL)
714 dotampered();
715 else
716 ILLCMD();
717 break;
718 }
719
720 if (hasmoved)
721 /* player has moved -- alter coordinates, and do random monster */
722 {
723 altercoordinates(x, y, A_SPECIFIC);
724
725 if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne)
726 encounter(-1);
727 }
728}
729/*\f*/
730/************************************************************************
731/
732/ FUNCTION NAME: titlelist()
733/
734/ FUNCTION: print title page
735/
736/ AUTHOR: E. A. Estes, 12/4/85
737/
738/ ARGUMENTS: none
739/
740/ RETURN VALUE: none
741/
742/ MODULES CALLED: fread(), fseek(), fopen(), fgets(), wmove(), strcpy(),
743/ fclose(), strlen(), waddstr(), sprintf(), wrefresh()
744/
745/ GLOBAL INPUTS: Lines, Other, *stdscr, Databuf[], *Playersfp
746/
747/ GLOBAL OUTPUTS: Lines
748/
749/ DESCRIPTION:
750/ Print important information about game, players, etc.
751/
752*************************************************************************/
753
754titlelist()
755{
756FILE *fp; /* used for opening various files */
757bool councilfound = FALSE; /* set if we find a member of the council */
758bool kingfound = FALSE; /* set if we find a king */
759double hiexp, nxtexp; /* used for finding the two highest players */
760double hilvl, nxtlvl; /* used for finding the two highest players */
761char hiname[21], nxtname[21];/* used for finding the two highest players */
762
763 mvaddstr(0, 14, "W e l c o m e t o P h a n t a s i a (vers. 3.3.2)!");
764
765 /* print message of the day */
766 if ((fp = fopen(_PATH_MOTD, "r")) != NULL
767 && fgets(Databuf, SZ_DATABUF, fp) != NULL)
768 {
769 mvaddstr(2, 40 - strlen(Databuf) / 2, Databuf);
770 fclose(fp);
771 }
772
773 /* search for king */
774 fseek(Playersfp, 0L, 0);
775 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
776 if (Other.p_specialtype == SC_KING && Other.p_status != S_NOTUSED)
777 /* found the king */
778 {
779 sprintf(Databuf, "The present ruler is %s Level:%.0f",
780 Other.p_name, Other.p_level);
781 mvaddstr(4, 40 - strlen(Databuf) / 2, Databuf);
782 kingfound = TRUE;
783 break;
784 }
785
786 if (!kingfound)
787 mvaddstr(4, 24, "There is no ruler at this time.");
788
789 /* search for valar */
790 fseek(Playersfp, 0L, 0);
791 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
792 if (Other.p_specialtype == SC_VALAR && Other.p_status != S_NOTUSED)
793 /* found the valar */
794 {
795 sprintf(Databuf, "The Valar is %s Login: %s", Other.p_name, Other.p_login);
796 mvaddstr(6, 40 - strlen(Databuf) / 2 , Databuf);
797 break;
798 }
799
800 /* search for council of the wise */
801 fseek(Playersfp, 0L, 0);
802 Lines = 10;
803 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
804 if (Other.p_specialtype == SC_COUNCIL && Other.p_status != S_NOTUSED)
805 /* found a member of the council */
806 {
807 if (!councilfound)
808 {
809 mvaddstr(8, 30, "Council of the Wise:");
810 councilfound = TRUE;
811 }
812
813 /* This assumes a finite (<=5) number of C.O.W.: */
814 sprintf(Databuf, "%s Login: %s", Other.p_name, Other.p_login);
815 mvaddstr(Lines++, 40 - strlen(Databuf) / 2, Databuf);
816 }
817
818 /* search for the two highest players */
819 nxtname[0] = hiname[0] = '\0';
820 hiexp = 0.0;
821 nxtlvl = hilvl = 0;
822
823 fseek(Playersfp, 0L, 0);
824 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
825 if (Other.p_experience > hiexp && Other.p_specialtype <= SC_KING && Other.p_status != S_NOTUSED)
826 /* highest found so far */
827 {
828 nxtexp = hiexp;
829 hiexp = Other.p_experience;
830 nxtlvl = hilvl;
831 hilvl = Other.p_level;
832 strcpy(nxtname, hiname);
833 strcpy(hiname, Other.p_name);
834 }
835 else if (Other.p_experience > nxtexp
836 && Other.p_specialtype <= SC_KING
837 && Other.p_status != S_NOTUSED)
838 /* next highest found so far */
839 {
840 nxtexp = Other.p_experience;
841 nxtlvl = Other.p_level;
842 strcpy(nxtname, Other.p_name);
843 }
844
845 mvaddstr(15, 28, "Highest characters are:");
846 sprintf(Databuf, "%s Level:%.0f and %s Level:%.0f",
847 hiname, hilvl, nxtname, nxtlvl);
848 mvaddstr(17, 40 - strlen(Databuf) / 2, Databuf);
849
850 /* print last to die */
851 if ((fp = fopen(_PATH_LASTDEAD,"r")) != NULL
852 && fgets(Databuf, SZ_DATABUF, fp) != NULL)
853 {
854 mvaddstr(19, 25, "The last character to die was:");
855 mvaddstr(20, 40 - strlen(Databuf) / 2,Databuf);
856 fclose(fp);
857 }
858
859 refresh();
860}
861/*\f*/
862/************************************************************************
863/
864/ FUNCTION NAME: recallplayer()
865/
866/ FUNCTION: find a character on file
867/
868/ AUTHOR: E. A. Estes, 12/4/85
869/
870/ ARGUMENTS: none
871/
872/ RETURN VALUE: none
873/
874/ MODULES CALLED: writerecord(), truncstring(), more(), death(), wmove(),
875/ wclear(), strcmp(), printw(), cleanup(), waddstr(), findname(), mvprintw(),
876/ getanswer(), getstring()
877/
878/ GLOBAL INPUTS: Player, *stdscr, Databuf[]
879/
880/ GLOBAL OUTPUTS: Echo, Player
881/
882/ DESCRIPTION:
883/ Search for a character of a certain name, and check password.
884/
885*************************************************************************/
886
887long
888recallplayer()
889{
890long loc = 0L; /* location in player file */
891int loop; /* loop counter */
892int ch; /* input */
893
894 clear();
895 mvprintw(10, 0, "What was your character's name ? ");
896 getstring(Databuf, SZ_NAME);
897 truncstring(Databuf);
898
899 if ((loc = findname(Databuf, &Player)) >= 0L)
900 /* found character */
901 {
902 Echo = FALSE;
903
904 for (loop = 0; loop < 2; ++loop)
905 {
906 /* prompt for password */
907 mvaddstr(11, 0, "Password ? ");
908 getstring(Databuf, SZ_PASSWORD);
909 if (strcmp(Databuf, Player.p_password) == 0)
910 /* password good */
911 {
912 Echo = TRUE;
913
914 if (Player.p_status != S_OFF)
915 /* player did not exit normally last time */
916 {
917 clear();
918 addstr("Your character did not exit normally last time.\n");
919 addstr("If you think you have good cause to have your character saved,\n");
920 printw("you may quit and mail your reason to 'root'.\n");
921 addstr("Otherwise, continuing spells certain death.\n");
922 addstr("Do you want to quit ? ");
923 ch = getanswer("YN", FALSE);
924 if (ch == 'Y')
925 {
926 Player.p_status = S_HUNGUP;
927 writerecord(&Player, loc);
928 cleanup(TRUE);
929 /*NOTREACHED*/
930 }
931 death("Stupidity");
932 /*NOTREACHED*/
933 }
934 return(loc);
935 }
936 else
937 mvaddstr(12, 0, "No good.\n");
938 }
939
940 Echo = TRUE;
941 }
942 else
943 mvaddstr(11, 0, "Not found.\n");
944
945 more(13);
946 return(-1L);
947}
948/*\f*/
949/************************************************************************
950/
951/ FUNCTION NAME: neatstuff()
952/
953/ FUNCTION: do random stuff
954/
955/ AUTHOR: E. A. Estes, 3/3/86
956/
957/ ARGUMENTS: none
958/
959/ RETURN VALUE: none
960/
961/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
962/ waddstr(), mvprintw(), getanswer()
963/
964/ GLOBAL INPUTS: Player, *stdscr, *Statptr
965/
966/ GLOBAL OUTPUTS: Player
967/
968/ DESCRIPTION:
969/ Handle gurus, medics, etc.
970/
971*************************************************************************/
972
973neatstuff()
974{
975double temp; /* for temporary calculations */
976int ch; /* input */
977
978 switch ((int) ROLL(0.0, 100.0))
979 {
980 case 1:
981 case 2:
982 if (Player.p_poison > 0.0)
983 {
984 mvaddstr(4, 0, "You've found a medic! How much will you offer to be cured ? ");
985 temp = floor(infloat());
986 if (temp < 0.0 || temp > Player.p_gold)
987 /* negative gold, or more than available */
988 {
989 mvaddstr(6, 0, "He was not amused, and made you worse.\n");
990 Player.p_poison += 1.0;
991 }
992 else if (drandom() / 2.0 > (temp + 1.0) / MAX(Player.p_gold, 1))
993 /* medic wants 1/2 of available gold */
994 mvaddstr(5, 0, "Sorry, he wasn't interested.\n");
995 else
996 {
997 mvaddstr(5, 0, "He accepted.");
998 Player.p_poison = MAX(0.0, Player.p_poison - 1.0);
999 Player.p_gold -= temp;
1000 }
1001 }
1002 break;
1003
1004 case 3:
1005 mvaddstr(4, 0, "You've been caught raping and pillaging!\n");
1006 Player.p_experience += 4000.0;
1007 Player.p_sin += 0.5;
1008 break;
1009
1010 case 4:
1011 temp = ROLL(10.0, 75.0);
1012 mvprintw(4, 0, "You've found %.0f gold pieces, want them ? ", temp);
1013 ch = getanswer("NY", FALSE);
1014
1015 if (ch == 'Y')
1016 collecttaxes(temp, 0.0);
1017 break;
1018
1019 case 5:
1020 if (Player.p_sin > 1.0)
1021 {
1022 mvaddstr(4, 0, "You've found a Holy Orb!\n");
1023 Player.p_sin -= 0.25;
1024 }
1025 break;
1026
1027 case 6:
1028 if (Player.p_poison < 1.0)
1029 {
1030 mvaddstr(4, 0, "You've been hit with a plague!\n");
1031 Player.p_poison += 1.0;
1032 }
1033 break;
1034
1035 case 7:
1036 mvaddstr(4, 0, "You've found some holy water.\n");
1037 ++Player.p_holywater;
1038 break;
1039
1040 case 8:
1041 mvaddstr(4, 0, "You've met a Guru. . .");
1042 if (drandom() * Player.p_sin > 1.0)
1043 addstr("You disgusted him with your sins!\n");
1044 else if (Player.p_poison > 0.0)
1045 {
1046 addstr("He looked kindly upon you, and cured you.\n");
1047 Player.p_poison = 0.0;
1048 }
1049 else
1050 {
1051 addstr("He rewarded you for your virtue.\n");
1052 Player.p_mana += 50.0;
1053 Player.p_shield += 2.0;
1054 }
1055 break;
1056
1057 case 9:
1058 mvaddstr(4, 0, "You've found an amulet.\n");
1059 ++Player.p_amulets;
1060 break;
1061
1062 case 10:
1063 if (Player.p_blindness)
1064 {
1065 mvaddstr(4, 0, "You've regained your sight!\n");
1066 Player.p_blindness = FALSE;
1067 }
1068 break;
1069
1070 default: /* deal with poison */
1071 if (Player.p_poison > 0.0)
1072 {
1073 temp = Player.p_poison * Statptr->c_weakness
1074 * Player.p_maxenergy / 600.0;
1075 if (Player.p_energy > Player.p_maxenergy / 10.0
1076 && temp + 5.0 < Player.p_energy)
1077 Player.p_energy -= temp;
1078 }
1079 break;
1080 }
1081}
1082/*\f*/
1083/************************************************************************
1084/
1085/ FUNCTION NAME: genchar()
1086/
1087/ FUNCTION: generate a random character
1088/
1089/ AUTHOR: E. A. Estes, 12/4/85
1090/
1091/ ARGUMENTS:
1092/ int type - ASCII value of character type to generate
1093/
1094/ RETURN VALUE: none
1095/
1096/ MODULES CALLED: floor(), drandom()
1097/
1098/ GLOBAL INPUTS: Wizard, Player, Stattable[]
1099/
1100/ GLOBAL OUTPUTS: Player
1101/
1102/ DESCRIPTION:
1103/ Use the lookup table for rolling stats.
1104/
1105*************************************************************************/
1106
1107genchar(type)
1108int type;
1109{
1110int subscript; /* used for subscripting into Stattable */
1111struct charstats *statptr;/* for pointing into Stattable */
1112
1113 subscript = type - '1';
1114
1115 if (subscript < C_MAGIC || subscript > C_EXPER)
1116 if (subscript != C_SUPER || !Wizard)
1117 /* fighter is default */
1118 subscript = C_FIGHTER;
1119
1120 statptr = &Stattable[subscript];
1121
1122 Player.p_quickness =
1123 ROLL(statptr->c_quickness.base, statptr->c_quickness.interval);
1124 Player.p_strength =
1125 ROLL(statptr->c_strength.base, statptr->c_strength.interval);
1126 Player.p_mana =
1127 ROLL(statptr->c_mana.base, statptr->c_mana.interval);
1128 Player.p_maxenergy =
1129 Player.p_energy =
1130 ROLL(statptr->c_energy.base, statptr->c_energy.interval);
1131 Player.p_brains =
1132 ROLL(statptr->c_brains.base, statptr->c_brains.interval);
1133 Player.p_magiclvl =
1134 ROLL(statptr->c_magiclvl.base, statptr->c_magiclvl.interval);
1135
1136 Player.p_type = subscript;
1137
1138 if (Player.p_type == C_HALFLING)
1139 /* give halfling some experience */
1140 Player.p_experience = ROLL(600.0, 200.0);
1141}
1142/*\f*/
1143/************************************************************************
1144/
1145/ FUNCTION NAME: playinit()
1146/
1147/ FUNCTION: initialize for playing game
1148/
1149/ AUTHOR: E. A. Estes, 12/4/85
1150/
1151/ ARGUMENTS: none
1152/
1153/ RETURN VALUE: none
1154/
1155/ MODULES CALLED: signal(), wclear(), noecho(), crmode(), initscr(),
1156/ wrefresh()
1157/
1158/ GLOBAL INPUTS: *stdscr, ill_sig()
1159/
1160/ GLOBAL OUTPUTS: Windows
1161/
1162/ DESCRIPTION:
1163/ Catch a bunch of signals, and turn on curses stuff.
1164/
1165*************************************************************************/
1166
1167playinit()
1168{
1169 /* catch/ingnore signals */
1170
1171#ifdef BSD41
1172 sigignore(SIGQUIT);
1173 sigignore(SIGALRM);
1174 sigignore(SIGTERM);
1175 sigignore(SIGTSTP);
1176 sigignore(SIGTTIN);
1177 sigignore(SIGTTOU);
1178 sighold(SIGINT);
1179 sigset(SIGHUP, ill_sig);
1180 sigset(SIGTRAP, ill_sig);
1181 sigset(SIGIOT, ill_sig);
1182 sigset(SIGEMT, ill_sig);
1183 sigset(SIGFPE, ill_sig);
1184 sigset(SIGBUS, ill_sig);
1185 sigset(SIGSEGV, ill_sig);
1186 sigset(SIGSYS, ill_sig);
1187 sigset(SIGPIPE, ill_sig);
1188#endif
1189#ifdef BSD42
1190 signal(SIGQUIT, ill_sig);
1191 signal(SIGALRM, SIG_IGN);
1192 signal(SIGTERM, SIG_IGN);
1193 signal(SIGTSTP, SIG_IGN);
1194 signal(SIGTTIN, SIG_IGN);
1195 signal(SIGTTOU, SIG_IGN);
1196 signal(SIGINT, ill_sig);
1197 signal(SIGHUP, SIG_DFL);
1198 signal(SIGTRAP, ill_sig);
1199 signal(SIGIOT, ill_sig);
1200 signal(SIGEMT, ill_sig);
1201 signal(SIGFPE, ill_sig);
1202 signal(SIGBUS, ill_sig);
1203 signal(SIGSEGV, ill_sig);
1204 signal(SIGSYS, ill_sig);
1205 signal(SIGPIPE, ill_sig);
1206#endif
1207#ifdef SYS3
1208 signal(SIGINT, SIG_IGN);
1209 signal(SIGQUIT, SIG_IGN);
1210 signal(SIGTERM, SIG_IGN);
1211 signal(SIGALRM, SIG_IGN);
1212 signal(SIGHUP, ill_sig);
1213 signal(SIGTRAP, ill_sig);
1214 signal(SIGIOT, ill_sig);
1215 signal(SIGEMT, ill_sig);
1216 signal(SIGFPE, ill_sig);
1217 signal(SIGBUS, ill_sig);
1218 signal(SIGSEGV, ill_sig);
1219 signal(SIGSYS, ill_sig);
1220 signal(SIGPIPE, ill_sig);
1221#endif
1222#ifdef SYS5
1223 signal(SIGINT, SIG_IGN);
1224 signal(SIGQUIT, SIG_IGN);
1225 signal(SIGTERM, SIG_IGN);
1226 signal(SIGALRM, SIG_IGN);
1227 signal(SIGHUP, ill_sig);
1228 signal(SIGTRAP, ill_sig);
1229 signal(SIGIOT, ill_sig);
1230 signal(SIGEMT, ill_sig);
1231 signal(SIGFPE, ill_sig);
1232 signal(SIGBUS, ill_sig);
1233 signal(SIGSEGV, ill_sig);
1234 signal(SIGSYS, ill_sig);
1235 signal(SIGPIPE, ill_sig);
1236#endif
1237
1238 initscr(); /* turn on curses */
1239 noecho(); /* do not echo input */
1240 crmode(); /* do not process erase, kill */
1241 clear();
1242 refresh();
1243 Windows = TRUE; /* mark the state */
1244}
1245
1246/*\f*/
1247/************************************************************************
1248/
1249/ FUNCTION NAME: cleanup()
1250/
1251/ FUNCTION: close some files, and maybe exit
1252/
1253/ AUTHOR: E. A. Estes, 12/4/85
1254/
1255/ ARGUMENTS:
1256/ bool doexit - exit flag
1257/
1258/ RETURN VALUE: none
1259/
1260/ MODULES CALLED: exit(), wmove(), fclose(), endwin(), nocrmode(), wrefresh()
1261/
1262/ GLOBAL INPUTS: *Energyvoidfp, LINES, *stdscr, Windows, *Monstfp,
1263/ *Messagefp, *Playersfp
1264/
1265/ GLOBAL OUTPUTS: none
1266/
1267/ DESCRIPTION:
1268/ Close all open files. If we are "in curses" terminate curses.
1269/ If 'doexit' is set, exit, otherwise return.
1270/
1271*************************************************************************/
1272
1273cleanup(doexit)
1274bool doexit;
1275{
1276 if (Windows)
1277 {
1278 move(LINES - 2, 0);
1279 refresh();
1280 nocrmode();
1281 endwin();
1282 }
1283
1284 if (Playersfp) {
1285 fclose(Playersfp);
1286 Playersfp = NULL;
1287 }
1288 if (Monstfp) {
1289 fclose(Monstfp);
1290 Monstfp = NULL;
1291 }
1292 if (Messagefp) {
1293 fclose(Messagefp);
1294 Messagefp = NULL;
1295 }
1296 if (Energyvoidfp) {
1297 fclose(Energyvoidfp);
1298 Energyvoidfp = NULL;
1299 }
1300
1301 if (doexit)
1302 exit(0);
1303 /*NOTREACHED*/
1304}