]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - phantasia/main.c
sprinkle static
[bsdgames-darwin.git] / phantasia / main.c
1 /* $NetBSD: main.c,v 1.22 2009/08/12 08:21:41 dholland Exp $ */
2
3 /*
4 * Phantasia 3.3.2 -- Interterminal fantasy game
5 *
6 * Edward A. Estes
7 * AT&T, March 12, 1986
8 */
9
10 /* DISCLAIMER:
11 *
12 * This game is distributed for free as is. It is not guaranteed to work
13 * in every conceivable environment. It is not even guaranteed to work
14 * in ANY environment.
15 *
16 * This game is distributed without notice of copyright, therefore it
17 * may be used in any manner the recipient sees fit. However, the
18 * author assumes no responsibility for maintaining or revising this
19 * game, in its original form, or any derivitives thereof.
20 *
21 * The author shall not be responsible for any loss, cost, or damage,
22 * including consequential damage, caused by reliance on this material.
23 *
24 * The author makes no warranties, express or implied, including warranties
25 * of merchantability or fitness for a particular purpose or use.
26 *
27 * AT&T is in no way connected with this game.
28 */
29
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <err.h>
33 #include <pwd.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 /*
57 * main.c Main routines for Phantasia
58 */
59
60 #include "include.h"
61 #undef bool
62 #include <curses.h>
63
64 static void genchar(int);
65 static void initialstate(void);
66 static void neatstuff(void);
67 static void playinit(void);
68 static void procmain(void);
69 static long recallplayer(void);
70 static long rollnewplayer(void);
71 static void titlelist(void);
72
73 int main(int, char **);
74
75 int
76 main(int argc, char **argv)
77 {
78 bool noheader = FALSE; /* set if don't want header */
79 bool headeronly = FALSE; /* set if only want header */
80 bool examine = FALSE; /* set if examine a character */
81 time_t seconds; /* for time of day */
82 double dtemp; /* for temporary calculations */
83
84 initialstate(); /* init globals */
85
86 /* process arguments */
87 while (--argc && (*++argv)[0] == '-')
88 switch ((*argv)[1]) {
89 case 's': /* short */
90 noheader = TRUE;
91 break;
92
93 case 'H': /* Header */
94 headeronly = TRUE;
95 break;
96
97 case 'a': /* all users */
98 activelist();
99 cleanup(TRUE);
100 /* NOTREACHED */
101
102 case 'p': /* purge old players */
103 purgeoldplayers();
104 cleanup(TRUE);
105 /* NOTREACHED */
106
107 case 'S': /* set 'Wizard' */
108 Wizard = !getuid();
109 break;
110
111 case 'x': /* examine */
112 examine = TRUE;
113 break;
114
115 case 'm': /* monsters */
116 monstlist();
117 cleanup(TRUE);
118 /* NOTREACHED */
119
120 case 'b': /* scoreboard */
121 scorelist();
122 cleanup(TRUE);
123 /* NOTREACHED */
124 }
125
126 if (!isatty(0)) /* don't let non-tty's play */
127 cleanup(TRUE);
128 /* NOTREACHED */
129
130 playinit(); /* set up to catch signals, init curses */
131
132 if (examine) {
133 changestats(FALSE);
134 cleanup(TRUE);
135 /* NOTREACHED */
136 }
137 if (!noheader) {
138 titlelist();
139 purgeoldplayers(); /* clean up old characters */
140 }
141 if (headeronly)
142 cleanup(TRUE);
143 /* NOTREACHED */
144
145 do
146 /* get the player structure filled */
147 {
148 Fileloc = -1L;
149
150 mvaddstr(22, 17, "Do you have a character to run [Q = Quit] ? ");
151
152 switch (getanswer("NYQ", FALSE)) {
153 case 'Y':
154 Fileloc = recallplayer();
155 break;
156
157 case 'Q':
158 cleanup(TRUE);
159 /* NOTREACHED */
160
161 default:
162 Fileloc = rollnewplayer();
163 break;
164 }
165 clear();
166 }
167 while (Fileloc < 0L);
168
169 if (Player.p_level > 5.0)
170 /* low level players have long timeout */
171 Timeout = TRUE;
172
173 /* update some important player statistics */
174 strlcpy(Player.p_login, Login, sizeof(Player.p_login));
175 time(&seconds);
176 Player.p_lastused = localtime(&seconds)->tm_yday;
177 Player.p_status = S_PLAYING;
178 writerecord(&Player, Fileloc);
179
180 Statptr = &Stattable[Player.p_type]; /* initialize pointer */
181
182 /* catch interrupts */
183 #ifdef BSD41
184 sigset(SIGINT, interrupt);
185 #endif
186 #ifdef BSD42
187 signal(SIGINT, interrupt);
188 #endif
189 #ifdef SYS3
190 signal(SIGINT, interrupt);
191 #endif
192 #ifdef SYS5
193 signal(SIGINT, interrupt);
194 #endif
195
196 altercoordinates(Player.p_x, Player.p_y, A_FORCED); /* set some flags */
197
198 clear();
199
200 for (;;)
201 /* loop forever, processing input */
202 {
203
204 adjuststats(); /* cleanup stats */
205
206 if (Throne && Player.p_crowns == 0 && Player.p_specialtype != SC_KING)
207 /* not allowed on throne -- move */
208 {
209 mvaddstr(5, 0, "You're not allowed in the Lord's Chamber without a crown.\n");
210 altercoordinates(0.0, 0.0, A_NEAR);
211 }
212 checktampered();/* check for energy voids, etc. */
213
214 if (Player.p_status != S_CLOAKED
215 /* not cloaked */
216 && (dtemp = fabs(Player.p_x)) == fabs(Player.p_y)
217 /* |x| = |y| */
218 && !Throne)
219 /* not on throne */
220 {
221 dtemp = sqrt(dtemp / 100.0);
222 if (floor(dtemp) == dtemp)
223 /* |x| / 100 == n*n; at a trading post */
224 {
225 tradingpost();
226 clear();
227 }
228 }
229 checkbattle(); /* check for player to player battle */
230 neatstuff(); /* gurus, medics, etc. */
231
232 if (Player.p_status == S_CLOAKED) {
233 /* costs 3 mana per turn to be cloaked */
234 if (Player.p_mana > 3.0)
235 Player.p_mana -= 3.0;
236 else
237 /* ran out of mana, uncloak */
238 {
239 Player.p_status = S_PLAYING;
240 Changed = TRUE;
241 }
242 }
243
244 if (Player.p_status != S_PLAYING && Player.p_status != S_CLOAKED)
245 /* change status back to S_PLAYING */
246 {
247 Player.p_status = S_PLAYING;
248 Changed = TRUE;
249 }
250 if (Changed)
251 /* update file only if important stuff has changed */
252 {
253 writerecord(&Player, Fileloc);
254 Changed = FALSE;
255 continue;
256 }
257 readmessage(); /* read message, if any */
258
259 displaystats(); /* print statistics */
260
261 move(6, 0);
262
263 if (Throne)
264 /* maybe make king, print prompt, etc. */
265 throneroom();
266
267 /* print status line */
268 addstr("1:Move 2:Players 3:Talk 4:Stats 5:Quit ");
269 if (Player.p_level >= MEL_CLOAK && Player.p_magiclvl >= ML_CLOAK)
270 addstr("6:Cloak ");
271 if (Player.p_level >= MEL_TELEPORT && Player.p_magiclvl >= ML_TELEPORT)
272 addstr("7:Teleport ");
273 if (Player.p_specialtype >= SC_COUNCIL || Wizard)
274 addstr("8:Intervene ");
275
276 procmain(); /* process input */
277 }
278 }
279
280 static void
281 initialstate(void)
282 {
283 struct stat sb;
284 struct passwd *pw;
285
286 Beyond = FALSE;
287 Marsh = FALSE;
288 Throne = FALSE;
289 Changed = FALSE;
290 Wizard = FALSE;
291 Timeout = FALSE;
292 Users = 0;
293 Windows = FALSE;
294 Echo = TRUE;
295
296 /* setup login name */
297 if ((Login = getlogin()) == NULL) {
298 pw = getpwuid(getuid());
299 if (pw == NULL) {
300 errx(1, "Who are you?");
301 }
302 Login = pw->pw_name;
303 }
304
305 /* open some files */
306 if ((Playersfp = fopen(_PATH_PEOPLE, "r+")) == NULL)
307 error(_PATH_PEOPLE);
308 /* NOTREACHED */
309 if (fileno(Playersfp) < 3)
310 exit(1);
311
312 if ((Monstfp = fopen(_PATH_MONST, "r+")) == NULL)
313 error(_PATH_MONST);
314 /* NOTREACHED */
315
316 if ((Messagefp = fopen(_PATH_MESS, "r")) == NULL)
317 error(_PATH_MESS);
318 /* NOTREACHED */
319
320 if ((Energyvoidfp = fopen(_PATH_VOID, "r+")) == NULL)
321 error(_PATH_VOID);
322 if (fstat(fileno(Energyvoidfp), &sb) == -1)
323 error("stat");
324 if (sb.st_size == 0) {
325 /* initialize grail to new location */
326 Enrgyvoid.ev_active = TRUE;
327 Enrgyvoid.ev_x = ROLL(-1.0e6, 2.0e6);
328 Enrgyvoid.ev_y = ROLL(-1.0e6, 2.0e6);
329 writevoid(&Enrgyvoid, 0L);
330 }
331
332 /* NOTREACHED */
333
334 srandom((unsigned) time(NULL)); /* prime random numbers */
335 }
336
337 static long
338 rollnewplayer(void)
339 {
340 int chartype; /* character type */
341 int ch; /* input */
342
343 initplayer(&Player); /* initialize player structure */
344
345 clear();
346 mvaddstr(4, 21, "Which type of character do you want:");
347 mvaddstr(8, 4,
348 "1:Magic User 2:Fighter 3:Elf 4:Dwarf 5:Halfling 6:Experimento ");
349 if (Wizard) {
350 addstr("7:Super ? ");
351 chartype = getanswer("1234567", FALSE);
352 } else {
353 addstr("? ");
354 chartype = getanswer("123456", FALSE);
355 }
356
357 do {
358 genchar(chartype); /* roll up a character */
359
360 /* print out results */
361 mvprintw(12, 14,
362 "Strength : %2.0f Quickness: %2.0f Mana : %2.0f\n",
363 Player.p_strength, Player.p_quickness, Player.p_mana);
364 mvprintw(13, 14,
365 "Energy Level: %2.0f Brains : %2.0f Magic Level: %2.0f\n",
366 Player.p_energy, Player.p_brains, Player.p_magiclvl);
367
368 if (Player.p_type == C_EXPER || Player.p_type == C_SUPER)
369 break;
370
371 mvaddstr(14, 14, "Type '1' to keep >");
372 ch = getanswer(" ", TRUE);
373 }
374 while (ch != '1');
375
376 if (Player.p_type == C_EXPER || Player.p_type == C_SUPER)
377 /* get coordinates for experimento */
378 for (;;) {
379 mvaddstr(16, 0, "Enter the X Y coordinates of your experimento ? ");
380 getstring(Databuf, SZ_DATABUF);
381 sscanf(Databuf, "%lf %lf", &Player.p_x, &Player.p_y);
382
383 if (fabs(Player.p_x) > D_EXPER || fabs(Player.p_y) > D_EXPER)
384 mvaddstr(17, 0, "Invalid coordinates. Try again.\n");
385 else
386 break;
387 }
388
389 for (;;)
390 /* name the new character */
391 {
392 mvprintw(18, 0,
393 "Give your character a name [up to %d characters] ? ", SZ_NAME - 1);
394 getstring(Player.p_name, SZ_NAME);
395 truncstring(Player.p_name); /* remove trailing blanks */
396
397 if (Player.p_name[0] == '\0')
398 /* no null names */
399 mvaddstr(19, 0, "Invalid name.");
400 else
401 if (findname(Player.p_name, &Other) >= 0L)
402 /* cannot have duplicate names */
403 mvaddstr(19, 0, "Name already in use.");
404 else
405 /* name is acceptable */
406 break;
407
408 addstr(" Pick another.\n");
409 }
410
411 /* get a password for character */
412 Echo = FALSE;
413
414 do {
415 mvaddstr(20, 0, "Give your character a password [up to 8 characters] ? ");
416 getstring(Player.p_password, SZ_PASSWORD);
417 mvaddstr(21, 0, "Enter again to verify: ");
418 getstring(Databuf, SZ_PASSWORD);
419 }
420 while (strcmp(Player.p_password, Databuf) != 0);
421
422 Echo = TRUE;
423
424 return (allocrecord());
425 }
426
427 static void
428 procmain(void)
429 {
430 int ch; /* input */
431 double x; /* desired new x coordinate */
432 double y; /* desired new y coordinate */
433 double temp; /* for temporary calculations */
434 FILE *fp; /* for opening files */
435 int loop; /* a loop counter */
436 bool hasmoved = FALSE; /* set if player has moved */
437
438 ch = inputoption();
439 mvaddstr(4, 0, "\n\n"); /* clear status area */
440
441 move(7, 0);
442 clrtobot(); /* clear data on bottom area of screen */
443
444 if (Player.p_specialtype == SC_VALAR && (ch == '1' || ch == '7'))
445 /* valar cannot move */
446 ch = ' ';
447
448 switch (ch) {
449 case 'K': /* move up/north */
450 case 'N':
451 x = Player.p_x;
452 y = Player.p_y + MAXMOVE();
453 hasmoved = TRUE;
454 break;
455
456 case 'J': /* move down/south */
457 case 'S':
458 x = Player.p_x;
459 y = Player.p_y - MAXMOVE();
460 hasmoved = TRUE;
461 break;
462
463 case 'L': /* move right/east */
464 case 'E':
465 x = Player.p_x + MAXMOVE();
466 y = Player.p_y;
467 hasmoved = TRUE;
468 break;
469
470 case 'H': /* move left/west */
471 case 'W':
472 x = Player.p_x - MAXMOVE();
473 y = Player.p_y;
474 hasmoved = TRUE;
475 break;
476
477 default: /* rest */
478 Player.p_energy += (Player.p_maxenergy + Player.p_shield) / 15.0
479 + Player.p_level / 3.0 + 2.0;
480 Player.p_energy =
481 MIN(Player.p_energy, Player.p_maxenergy + Player.p_shield);
482
483 if (Player.p_status != S_CLOAKED)
484 /* cannot find mana if cloaked */
485 {
486 Player.p_mana += (Circle + Player.p_level) / 4.0;
487
488 if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne)
489 /* wandering monster */
490 encounter(-1);
491 }
492 break;
493
494 case 'X': /* change/examine a character */
495 changestats(TRUE);
496 break;
497
498 case '1': /* move */
499 for (loop = 3; loop; --loop) {
500 mvaddstr(4, 0, "X Y Coordinates ? ");
501 getstring(Databuf, SZ_DATABUF);
502
503 if (sscanf(Databuf, "%lf %lf", &x, &y) != 2)
504 mvaddstr(5, 0, "Try again\n");
505 else
506 if (distance(Player.p_x, x, Player.p_y, y) > MAXMOVE())
507 ILLMOVE();
508 else {
509 hasmoved = TRUE;
510 break;
511 }
512 }
513 break;
514
515 case '2': /* players */
516 userlist(TRUE);
517 break;
518
519 case '3': /* message */
520 mvaddstr(4, 0, "Message ? ");
521 getstring(Databuf, SZ_DATABUF);
522 /* we open the file for writing to erase any data which is
523 * already there */
524 fp = fopen(_PATH_MESS, "w");
525 if (Databuf[0] != '\0')
526 fprintf(fp, "%s: %s", Player.p_name, Databuf);
527 fclose(fp);
528 break;
529
530 case '4': /* stats */
531 allstatslist();
532 break;
533
534 case '5': /* good-bye */
535 leavegame();
536 /* NOTREACHED */
537
538 case '6': /* cloak */
539 if (Player.p_level < MEL_CLOAK || Player.p_magiclvl < ML_CLOAK)
540 ILLCMD();
541 else
542 if (Player.p_status == S_CLOAKED)
543 Player.p_status = S_PLAYING;
544 else
545 if (Player.p_mana < MM_CLOAK)
546 mvaddstr(5, 0, "No mana left.\n");
547 else {
548 Changed = TRUE;
549 Player.p_mana -= MM_CLOAK;
550 Player.p_status = S_CLOAKED;
551 }
552 break;
553
554 case '7': /* teleport */
555 /*
556 * conditions for teleport
557 * - 20 per (level plus magic level)
558 * - OR council of the wise or valar or ex-valar
559 * - OR transport from throne
560 * transports from throne cost no mana
561 */
562 if (Player.p_level < MEL_TELEPORT || Player.p_magiclvl < ML_TELEPORT)
563 ILLCMD();
564 else
565 for (loop = 3; loop; --loop) {
566 mvaddstr(4, 0, "X Y Coordinates ? ");
567 getstring(Databuf, SZ_DATABUF);
568
569 if (sscanf(Databuf, "%lf %lf", &x, &y) == 2) {
570 temp = distance(Player.p_x, x, Player.p_y, y);
571 if (!Throne
572 /* can transport anywhere from throne */
573 && Player.p_specialtype <= SC_COUNCIL
574 /* council, valar can transport
575 * anywhere */
576 && temp > (Player.p_level + Player.p_magiclvl) * 20.0)
577 /* can only move 20 per exp.
578 * level + mag. level */
579 ILLMOVE();
580 else {
581 temp = (temp / 75.0 + 1.0) * 20.0; /* mana used */
582
583 if (!Throne && temp > Player.p_mana)
584 mvaddstr(5, 0, "Not enough power for that distance.\n");
585 else {
586 if (!Throne)
587 Player.p_mana -= temp;
588 hasmoved = TRUE;
589 break;
590 }
591 }
592 }
593 }
594 break;
595
596 case 'C':
597 case '9': /* monster */
598 if (Throne)
599 /* no monsters while on throne */
600 mvaddstr(5, 0, "No monsters in the chamber!\n");
601 else
602 if (Player.p_specialtype != SC_VALAR)
603 /* the valar cannot call monsters */
604 {
605 Player.p_sin += 1e-6;
606 encounter(-1);
607 }
608 break;
609
610 case '0': /* decree */
611 if (Wizard || (Player.p_specialtype == SC_KING && Throne))
612 /* kings must be on throne to decree */
613 dotampered();
614 else
615 ILLCMD();
616 break;
617
618 case '8': /* intervention */
619 if (Wizard || Player.p_specialtype >= SC_COUNCIL)
620 dotampered();
621 else
622 ILLCMD();
623 break;
624 }
625
626 if (hasmoved)
627 /* player has moved -- alter coordinates, and do random
628 * monster */
629 {
630 altercoordinates(x, y, A_SPECIFIC);
631
632 if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne)
633 encounter(-1);
634 }
635 }
636
637 static void
638 titlelist(void)
639 {
640 FILE *fp; /* used for opening various files */
641 bool councilfound = FALSE; /* set if we find a member of the
642 * council */
643 bool kingfound = FALSE; /* set if we find a king */
644 double hiexp, nxtexp; /* used for finding the two highest players */
645 double hilvl, nxtlvl; /* used for finding the two highest players */
646 char hiname[21], nxtname[21]; /* used for finding the two
647 * highest players */
648
649 nxtexp = 0;
650 mvaddstr(0, 14,
651 "W e l c o m e t o P h a n t a s i a (vers. 3.3.2)!");
652
653 /* print message of the day */
654 if ((fp = fopen(_PATH_MOTD, "r")) != NULL
655 && fgets(Databuf, SZ_DATABUF, fp) != NULL) {
656 mvaddstr(2, 40 - strlen(Databuf) / 2, Databuf);
657 fclose(fp);
658 }
659 /* search for king */
660 fseek(Playersfp, 0L, SEEK_SET);
661 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
662 if (Other.p_specialtype == SC_KING &&
663 Other.p_status != S_NOTUSED)
664 /* found the king */
665 {
666 snprintf(Databuf, SZ_DATABUF,
667 "The present ruler is %s Level:%.0f",
668 Other.p_name, Other.p_level);
669 mvaddstr(4, 40 - strlen(Databuf) / 2, Databuf);
670 kingfound = TRUE;
671 break;
672 }
673 if (!kingfound)
674 mvaddstr(4, 24, "There is no ruler at this time.");
675
676 /* search for valar */
677 fseek(Playersfp, 0L, SEEK_SET);
678 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
679 if (Other.p_specialtype == SC_VALAR && Other.p_status != S_NOTUSED)
680 /* found the valar */
681 {
682 snprintf(Databuf, SZ_DATABUF,
683 "The Valar is %s Login: %s",
684 Other.p_name, Other.p_login);
685 mvaddstr(6, 40 - strlen(Databuf) / 2, Databuf);
686 break;
687 }
688 /* search for council of the wise */
689 fseek(Playersfp, 0L, SEEK_SET);
690 Lines = 10;
691 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
692 if (Other.p_specialtype == SC_COUNCIL && Other.p_status != S_NOTUSED)
693 /* found a member of the council */
694 {
695 if (!councilfound) {
696 mvaddstr(8, 30, "Council of the Wise:");
697 councilfound = TRUE;
698 }
699 /* This assumes a finite (<=5) number of C.O.W.: */
700 snprintf(Databuf, SZ_DATABUF,
701 "%s Login: %s", Other.p_name, Other.p_login);
702 mvaddstr(Lines++, 40 - strlen(Databuf) / 2, Databuf);
703 }
704 /* search for the two highest players */
705 nxtname[0] = hiname[0] = '\0';
706 hiexp = 0.0;
707 nxtlvl = hilvl = 0;
708
709 fseek(Playersfp, 0L, SEEK_SET);
710 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
711 if (Other.p_experience > hiexp && Other.p_specialtype <= SC_KING && Other.p_status != S_NOTUSED)
712 /* highest found so far */
713 {
714 nxtexp = hiexp;
715 hiexp = Other.p_experience;
716 nxtlvl = hilvl;
717 hilvl = Other.p_level;
718 strcpy(nxtname, hiname);
719 strcpy(hiname, Other.p_name);
720 } else
721 if (Other.p_experience > nxtexp
722 && Other.p_specialtype <= SC_KING
723 && Other.p_status != S_NOTUSED)
724 /* next highest found so far */
725 {
726 nxtexp = Other.p_experience;
727 nxtlvl = Other.p_level;
728 strcpy(nxtname, Other.p_name);
729 }
730 mvaddstr(15, 28, "Highest characters are:");
731 snprintf(Databuf, SZ_DATABUF,
732 "%s Level:%.0f and %s Level:%.0f",
733 hiname, hilvl, nxtname, nxtlvl);
734 mvaddstr(17, 40 - strlen(Databuf) / 2, Databuf);
735
736 /* print last to die */
737 if ((fp = fopen(_PATH_LASTDEAD, "r")) != NULL
738 && fgets(Databuf, SZ_DATABUF, fp) != NULL) {
739 mvaddstr(19, 25, "The last character to die was:");
740 mvaddstr(20, 40 - strlen(Databuf) / 2, Databuf);
741 }
742 if (fp)
743 fclose(fp);
744 refresh();
745 }
746
747 static long
748 recallplayer(void)
749 {
750 long loc = 0L; /* location in player file */
751 int loop; /* loop counter */
752 int ch; /* input */
753
754 clear();
755 mvprintw(10, 0, "What was your character's name ? ");
756 getstring(Databuf, SZ_NAME);
757 truncstring(Databuf);
758
759 if ((loc = findname(Databuf, &Player)) >= 0L)
760 /* found character */
761 {
762 Echo = FALSE;
763
764 for (loop = 0; loop < 2; ++loop) {
765 /* prompt for password */
766 mvaddstr(11, 0, "Password ? ");
767 getstring(Databuf, SZ_PASSWORD);
768 if (strcmp(Databuf, Player.p_password) == 0)
769 /* password good */
770 {
771 Echo = TRUE;
772
773 if (Player.p_status != S_OFF)
774 /* player did not exit normally last
775 * time */
776 {
777 clear();
778 addstr("Your character did not exit normally last time.\n");
779 addstr("If you think you have good cause to have your character saved,\n");
780 printw("you may quit and mail your reason to 'root'.\n");
781 addstr("Otherwise, continuing spells certain death.\n");
782 addstr("Do you want to quit ? ");
783 ch = getanswer("YN", FALSE);
784 if (ch == 'Y') {
785 Player.p_status = S_HUNGUP;
786 writerecord(&Player, loc);
787 cleanup(TRUE);
788 /* NOTREACHED */
789 }
790 death("Stupidity");
791 /* NOTREACHED */
792 }
793 return (loc);
794 } else
795 mvaddstr(12, 0, "No good.\n");
796 }
797
798 Echo = TRUE;
799 } else
800 mvaddstr(11, 0, "Not found.\n");
801
802 more(13);
803 return (-1L);
804 }
805
806 static void
807 neatstuff(void)
808 {
809 double temp; /* for temporary calculations */
810 int ch; /* input */
811
812 switch ((int) ROLL(0.0, 100.0)) {
813 case 1:
814 case 2:
815 if (Player.p_poison > 0.0) {
816 mvaddstr(4, 0, "You've found a medic! How much will you offer to be cured ? ");
817 temp = floor(infloat());
818 if (temp < 0.0 || temp > Player.p_gold)
819 /* negative gold, or more than available */
820 {
821 mvaddstr(6, 0, "He was not amused, and made you worse.\n");
822 Player.p_poison += 1.0;
823 } else
824 if (drandom() / 2.0 > (temp + 1.0) / MAX(Player.p_gold, 1))
825 /* medic wants 1/2 of available gold */
826 mvaddstr(5, 0, "Sorry, he wasn't interested.\n");
827 else {
828 mvaddstr(5, 0, "He accepted.");
829 Player.p_poison = MAX(0.0, Player.p_poison - 1.0);
830 Player.p_gold -= temp;
831 }
832 }
833 break;
834
835 case 3:
836 mvaddstr(4, 0, "You've been caught raping and pillaging!\n");
837 Player.p_experience += 4000.0;
838 Player.p_sin += 0.5;
839 break;
840
841 case 4:
842 temp = ROLL(10.0, 75.0);
843 mvprintw(4, 0, "You've found %.0f gold pieces, want them ? ", temp);
844 ch = getanswer("NY", FALSE);
845
846 if (ch == 'Y')
847 collecttaxes(temp, 0.0);
848 break;
849
850 case 5:
851 if (Player.p_sin > 1.0) {
852 mvaddstr(4, 0, "You've found a Holy Orb!\n");
853 Player.p_sin -= 0.25;
854 }
855 break;
856
857 case 6:
858 if (Player.p_poison < 1.0) {
859 mvaddstr(4, 0, "You've been hit with a plague!\n");
860 Player.p_poison += 1.0;
861 }
862 break;
863
864 case 7:
865 mvaddstr(4, 0, "You've found some holy water.\n");
866 ++Player.p_holywater;
867 break;
868
869 case 8:
870 mvaddstr(4, 0, "You've met a Guru. . .");
871 if (drandom() * Player.p_sin > 1.0)
872 addstr("You disgusted him with your sins!\n");
873 else
874 if (Player.p_poison > 0.0) {
875 addstr("He looked kindly upon you, and cured you.\n");
876 Player.p_poison = 0.0;
877 } else {
878 addstr("He rewarded you for your virtue.\n");
879 Player.p_mana += 50.0;
880 Player.p_shield += 2.0;
881 }
882 break;
883
884 case 9:
885 mvaddstr(4, 0, "You've found an amulet.\n");
886 ++Player.p_amulets;
887 break;
888
889 case 10:
890 if (Player.p_blindness) {
891 mvaddstr(4, 0, "You've regained your sight!\n");
892 Player.p_blindness = FALSE;
893 }
894 break;
895
896 default: /* deal with poison */
897 if (Player.p_poison > 0.0) {
898 temp = Player.p_poison * Statptr->c_weakness
899 * Player.p_maxenergy / 600.0;
900 if (Player.p_energy > Player.p_maxenergy / 10.0
901 && temp + 5.0 < Player.p_energy)
902 Player.p_energy -= temp;
903 }
904 break;
905 }
906 }
907
908 static void
909 genchar(int type)
910 {
911 int subscript; /* used for subscripting into Stattable */
912 const struct charstats *statptr; /* for pointing into Stattable */
913
914 subscript = type - '1';
915
916 if (subscript < C_MAGIC || subscript > C_EXPER)
917 if (subscript != C_SUPER || !Wizard)
918 /* fighter is default */
919 subscript = C_FIGHTER;
920
921 statptr = &Stattable[subscript];
922
923 Player.p_quickness =
924 ROLL(statptr->c_quickness.base, statptr->c_quickness.interval);
925 Player.p_strength =
926 ROLL(statptr->c_strength.base, statptr->c_strength.interval);
927 Player.p_mana =
928 ROLL(statptr->c_mana.base, statptr->c_mana.interval);
929 Player.p_maxenergy =
930 Player.p_energy =
931 ROLL(statptr->c_energy.base, statptr->c_energy.interval);
932 Player.p_brains =
933 ROLL(statptr->c_brains.base, statptr->c_brains.interval);
934 Player.p_magiclvl =
935 ROLL(statptr->c_magiclvl.base, statptr->c_magiclvl.interval);
936
937 Player.p_type = subscript;
938
939 if (Player.p_type == C_HALFLING)
940 /* give halfling some experience */
941 Player.p_experience = ROLL(600.0, 200.0);
942 }
943
944 static void
945 playinit(void)
946 {
947 /* catch/ingnore signals */
948
949 #ifdef BSD41
950 sigignore(SIGQUIT);
951 sigignore(SIGALRM);
952 sigignore(SIGTERM);
953 sigignore(SIGTSTP);
954 sigignore(SIGTTIN);
955 sigignore(SIGTTOU);
956 sighold(SIGINT);
957 sigset(SIGHUP, ill_sig);
958 sigset(SIGTRAP, ill_sig);
959 sigset(SIGIOT, ill_sig);
960 sigset(SIGEMT, ill_sig);
961 sigset(SIGFPE, ill_sig);
962 sigset(SIGBUS, ill_sig);
963 sigset(SIGSEGV, ill_sig);
964 sigset(SIGSYS, ill_sig);
965 sigset(SIGPIPE, ill_sig);
966 #endif
967 #ifdef BSD42
968 signal(SIGQUIT, ill_sig);
969 signal(SIGALRM, SIG_IGN);
970 signal(SIGTERM, SIG_IGN);
971 signal(SIGTSTP, SIG_IGN);
972 signal(SIGTTIN, SIG_IGN);
973 signal(SIGTTOU, SIG_IGN);
974 signal(SIGINT, ill_sig);
975 signal(SIGHUP, SIG_DFL);
976 signal(SIGTRAP, ill_sig);
977 signal(SIGIOT, ill_sig);
978 signal(SIGEMT, ill_sig);
979 signal(SIGFPE, ill_sig);
980 signal(SIGBUS, ill_sig);
981 signal(SIGSEGV, ill_sig);
982 signal(SIGSYS, ill_sig);
983 signal(SIGPIPE, ill_sig);
984 #endif
985 #ifdef SYS3
986 signal(SIGINT, SIG_IGN);
987 signal(SIGQUIT, SIG_IGN);
988 signal(SIGTERM, SIG_IGN);
989 signal(SIGALRM, SIG_IGN);
990 signal(SIGHUP, ill_sig);
991 signal(SIGTRAP, ill_sig);
992 signal(SIGIOT, ill_sig);
993 signal(SIGEMT, ill_sig);
994 signal(SIGFPE, ill_sig);
995 signal(SIGBUS, ill_sig);
996 signal(SIGSEGV, ill_sig);
997 signal(SIGSYS, ill_sig);
998 signal(SIGPIPE, ill_sig);
999 #endif
1000 #ifdef SYS5
1001 signal(SIGINT, SIG_IGN);
1002 signal(SIGQUIT, SIG_IGN);
1003 signal(SIGTERM, SIG_IGN);
1004 signal(SIGALRM, SIG_IGN);
1005 signal(SIGHUP, ill_sig);
1006 signal(SIGTRAP, ill_sig);
1007 signal(SIGIOT, ill_sig);
1008 signal(SIGEMT, ill_sig);
1009 signal(SIGFPE, ill_sig);
1010 signal(SIGBUS, ill_sig);
1011 signal(SIGSEGV, ill_sig);
1012 signal(SIGSYS, ill_sig);
1013 signal(SIGPIPE, ill_sig);
1014 #endif
1015
1016 if (!initscr()) { /* turn on curses */
1017 fprintf(stderr, "couldn't initialize screen\n");
1018 exit (0);
1019 }
1020 noecho(); /* do not echo input */
1021 cbreak(); /* do not process erase, kill */
1022 clear();
1023 refresh();
1024 Windows = TRUE; /* mark the state */
1025 }
1026
1027 void
1028 cleanup(int doexit)
1029 {
1030 if (Windows) {
1031 move(LINES - 2, 0);
1032 refresh();
1033 nocbreak();
1034 endwin();
1035 }
1036 if (Playersfp)
1037 fclose(Playersfp);
1038 if (Monstfp)
1039 fclose(Monstfp);
1040 if (Messagefp)
1041 fclose(Messagefp);
1042 if (Energyvoidfp)
1043 fclose(Energyvoidfp);
1044
1045 if (doexit)
1046 exit(0);
1047 /* NOTREACHED */
1048 }