Update default make.conf and its manpage:
[dragonfly.git] / games / phantasia / interplayer.c
1 /*
2  * interplayer.c - player to player routines for Phantasia
3  *
4  * $FreeBSD: src/games/phantasia/interplayer.c,v 1.6 1999/11/16 02:57:33 billf Exp $
5  * $DragonFly: src/games/phantasia/interplayer.c,v 1.3 2005/05/31 00:06:26 swildner Exp $
6  */
7
8 #include <string.h>
9 #include "include.h"
10
11 /* functions which we need to know about */
12 /* fight.c */
13 extern  void    encounter(int);
14 /* io.c */
15 extern  int     getanswer(const char *, bool);
16 extern  void    getstring(char *, int);
17 extern  double  infloat(void);
18 extern  int     inputoption(void);
19 extern  void    more(int);
20 /* misc.c */
21 extern  void    altercoordinates(double, double, int);
22 extern  void    collecttaxes(double, double);
23 extern  void    death(const char *);
24 extern  const char      *descrlocation(struct player *, bool);
25 extern  const char      *descrstatus(struct player *);
26 extern  const char      *descrtype(struct player *, bool);
27 extern  void    displaystats(void);
28 extern  double  distance(double, double, double, double);
29 extern  long    findname(char *, struct player *);
30 extern  void    readmessage(void);
31 extern  void    readrecord(struct player *, long);
32 extern  void    truncstring(char *);
33 extern  void    writerecord(struct player *, long);
34 /* phantglobs.c */
35 extern  double  drandom(void);
36
37 void    checkbattle(void);
38 void    battleplayer(long);
39 void    myturn(void);
40 void    checktampered(void);
41 void    tampered(int, double, double);
42 void    userlist(bool);
43 void    throneroom(void);
44 void    dotampered(void);
45 void    writevoid(struct energyvoid *, long);
46 size_t  allocvoid(void);
47
48 /************************************************************************
49 /
50 / FUNCTION NAME: checkbattle()
51 /
52 / FUNCTION: check to see if current player should battle another
53 /
54 / AUTHOR: E. A. Estes, 12/4/85
55 /
56 / ARGUMENTS: none
57 /
58 / RETURN VALUE: none
59 /
60 / MODULES CALLED: battleplayer(), fread(), fseek()
61 /
62 / GLOBAL INPUTS: Other, Users, Player, Fileloc, *Playersfp
63 /
64 / GLOBAL OUTPUTS: Users
65 /
66 / DESCRIPTION:
67 /       Seach player file for a foe at the same coordinates as the
68 /       current player.
69 /       Also update user count.
70 /
71 *************************************************************************/
72
73 void
74 checkbattle(void)
75 {
76 long    foeloc = 0L;            /* location in file of person to fight */
77
78     Users = 0;
79     fseek(Playersfp, 0L, 0);
80
81     while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
82         {
83         if (Other.p_status != S_OFF
84             && Other.p_status != S_NOTUSED
85             && Other.p_status != S_HUNGUP
86             && (Other.p_status != S_CLOAKED || Other.p_specialtype != SC_VALAR))
87             /* player is on and not a cloaked valar */
88             {
89             ++Users;
90
91             if (Player.p_x == Other.p_x
92                 && Player.p_y == Other.p_y
93                 /* same coordinates */
94                 && foeloc != Fileloc
95                 /* not self */
96                 && Player.p_status == S_PLAYING
97                 && (Other.p_status == S_PLAYING || Other.p_status == S_INBATTLE)
98                 /* both are playing */
99                 && Other.p_specialtype != SC_VALAR
100                 && Player.p_specialtype != SC_VALAR)
101                 /* neither is valar */
102                 {
103                 battleplayer(foeloc);
104                 return;
105                 }
106             }
107         foeloc += SZ_PLAYERSTRUCT;
108         }
109 }
110 /*\f*/
111 /************************************************************************
112 /
113 / FUNCTION NAME: battleplayer()
114 /
115 / FUNCTION: inter-terminal battle with another player
116 /
117 / AUTHOR: E. A. Estes, 2/15/86
118 /
119 / ARGUMENTS:
120 /       long foeplace - location in player file of person to battle
121 /
122 / RETURN VALUE: none
123 /
124 / MODULES CALLED: readrecord(), readmessage(), writerecord(), collecttaxes(),
125 /       displaystats(), fabs(), more(), death(), sleep(), wmove(), waddch(), printw(),
126 /       myturn(), altercoordinates(), waddstr(), wrefresh(), mvprintw(),
127 /       getanswer(), wclrtoeol(), wclrtobot()
128 /
129 / GLOBAL INPUTS: Foestrikes, LINES, Lines, Other, Shield, Player, *stdscr,
130 /       Fileloc, *Enemyname
131 /
132 / GLOBAL OUTPUTS: Foestrikes, Lines, Shield, Player, Luckout, *Enemyname
133 /
134 / DESCRIPTION:
135 /       Inter-terminal battle is a very fragile and slightly klugy thing.
136 /       At any time, one player is master and the other is slave.
137 /       We pick who is master first by speed and level.  After that,
138 /       the slave waits for the master to relinquish its turn, and
139 /       the slave becomes master, and so on.
140 /
141 /       The items in the player structure which control the handshake are:
142 /           p_tampered:
143 /               master increments this to relinquish control
144 /           p_istat:
145 /               master sets this to specify particular action
146 /           p_1scratch:
147 /               set to total damage inflicted so far; changes to indicate action
148 /
149 *************************************************************************/
150
151 void
152 battleplayer(long foeplace)
153 {
154 double  dtemp;          /* for temporary calculations */
155 double  oldhits = 0.0;  /* previous damage inflicted by foe */
156 int     loop;   /* for timing out */
157 int     ch;             /* input */
158 short   oldtampered;    /* old value of foe's p_tampered */
159
160     Lines = 8;
161     Luckout = FALSE;
162     mvaddstr(4, 0, "Preparing for battle!\n");
163     refresh();
164
165 #ifdef SYS5
166     flushinp();
167 #endif
168
169     /* set up variables, file, etc. */
170     Player.p_status = S_INBATTLE;
171     Shield = Player.p_energy;
172
173     /* if p_tampered is not 0, someone else may try to change it (king, etc.) */
174     Player.p_tampered = oldtampered = 1;
175     Player.p_1scratch = 0.0;
176     Player.p_istat = I_OFF;
177
178     readrecord(&Other, foeplace);
179     if (fabs(Player.p_level - Other.p_level) > 20.0)
180         /* see if players are greatly mismatched */
181         {
182         dtemp = (Player.p_level - Other.p_level) / MAX(Player.p_level, Other.p_level);
183         if (dtemp < -0.5)
184             /* foe outweighs this one */
185             Player.p_speed *= 2.0;
186         }
187
188     writerecord(&Player, Fileloc);              /* write out all our info */
189
190     if (Player.p_blindness)
191         Enemyname = "someone";
192     else
193         Enemyname = Other.p_name;
194
195     mvprintw(6, 0, "You have encountered %s   Level: %.0f\n", Enemyname, Other.p_level);
196     refresh();
197
198     for (loop = 0; Other.p_status != S_INBATTLE && loop < 30; ++loop)
199         /* wait for foe to respond */
200         {
201         readrecord(&Other, foeplace);
202         sleep(1);
203         }
204
205     if (Other.p_status != S_INBATTLE)
206         /* foe did not respond */
207         {
208         mvprintw(5, 0, "%s is not responding.\n", Enemyname);
209         goto LEAVE;
210         }
211     /* else, we are ready to battle */
212
213     move(4, 0);
214     clrtoeol();
215
216     /*
217      * determine who is first master
218      * if neither player is faster, check level
219      * if neither level is greater, battle is not allowed
220      * (this should never happen, but we have to handle it)
221      */
222     if (Player.p_speed > Other.p_speed)
223         Foestrikes = FALSE;
224     else if (Other.p_speed > Player.p_speed)
225         Foestrikes = TRUE;
226     else if (Player.p_level > Other.p_level)
227         Foestrikes = FALSE;
228     else if (Other.p_level > Player.p_level)
229         Foestrikes = TRUE;
230     else
231         /* no one is faster */
232         {
233         printw("You can't fight %s yet.", Enemyname);
234         goto LEAVE;
235         }
236
237     for (;;)
238         {
239         displaystats();
240         readmessage();
241         mvprintw(1, 26, "%20.0f", Shield);      /* overprint energy */
242
243         if (!Foestrikes)
244             /* take action against foe */
245             myturn();
246         else
247             /* wait for foe to take action */
248             {
249             mvaddstr(4, 0, "Waiting...\n");
250             clrtoeol();
251             refresh();
252
253             for (loop = 0; loop < 20; ++loop)
254                 /* wait for foe to act */
255                 {
256                 readrecord(&Other, foeplace);
257                 if (Other.p_1scratch != oldhits)
258                     /* p_1scratch changes to indicate action */
259                     break;
260                 else
261                     /* wait and try again */
262                     {
263                     sleep(1);
264                     addch('.');
265                     refresh();
266                     }
267                 }
268
269             if (Other.p_1scratch == oldhits)
270                 {
271                 /* timeout */
272                 mvaddstr(22, 0, "Timeout: waiting for response.  Do you want to wait ? ");
273                 ch = getanswer("NY", FALSE);
274                 move(22, 0);
275                 clrtobot();
276                 if (ch == 'Y')
277                     continue;
278                 else
279                     break;
280                 }
281             else
282                 /* foe took action */
283                 {
284                 switch (Other.p_istat)
285                     {
286                     case I_RAN:         /* foe ran away */
287                         mvprintw(Lines++, 0, "%s ran away!", Enemyname);
288                         break;
289
290                     case I_STUCK:       /* foe tried to run, but couldn't */
291                         mvprintw(Lines++, 0, "%s tried to run away.", Enemyname);
292                         break;
293
294                     case I_BLEWIT:      /* foe tried to luckout, but didn't */
295                         mvprintw(Lines++, 0, "%s tried to luckout!", Enemyname);
296                         break;
297
298                     default:
299                         dtemp = Other.p_1scratch - oldhits;
300                         mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, dtemp);
301                         Shield -= dtemp;
302                         break;
303                     }
304
305                 oldhits = Other.p_1scratch;     /* keep track of old hits */
306
307                 if (Other.p_tampered != oldtampered)
308                     /* p_tampered changes to relinquish turn */
309                     {
310                     oldtampered = Other.p_tampered;
311                     Foestrikes = FALSE;
312                     }
313                 }
314             }
315
316         /* decide what happens next */
317         refresh();
318         if (Lines > LINES - 2)
319             {
320             more(Lines);
321             move(Lines = 8, 0);
322             clrtobot();
323             }
324
325         if (Other.p_istat == I_KILLED || Shield < 0.0)
326             /* we died */
327             {
328             Shield = -2.0;              /* insure this value is negative */
329             break;
330             }
331
332         if (Player.p_istat == I_KILLED)
333             /* we killed foe; award treasre */
334             {
335             mvprintw(Lines++, 0, "You killed %s!", Enemyname);
336             Player.p_experience += Other.p_experience;
337             Player.p_crowns += (Player.p_level < 1000.0) ? Other.p_crowns : 0;
338             Player.p_amulets += Other.p_amulets;
339             Player.p_charms += Other.p_charms;
340             collecttaxes(Other.p_gold, Other.p_gems);
341             Player.p_sword = MAX(Player.p_sword, Other.p_sword);
342             Player.p_shield = MAX(Player.p_shield, Other.p_shield);
343             Player.p_quksilver = MAX(Player.p_quksilver, Other.p_quksilver);
344             if (Other.p_virgin && !Player.p_virgin)
345                 {
346                 mvaddstr(Lines++, 0, "You have rescued a virgin.  Will you be honorable ? ");
347                 if ((ch = getanswer("YN", FALSE)) == 'Y')
348                     Player.p_virgin = TRUE;
349                 else
350                     {
351                     ++Player.p_sin;
352                     Player.p_experience += 8000.0;
353                     }
354                 }
355             sleep(3);                   /* give other person time to die */
356             break;
357             }
358         else if (Player.p_istat == I_RAN || Other.p_istat == I_RAN)
359             /* either player ran away */
360             break;
361         }
362
363 LEAVE:
364     /* clean up things and leave */
365     writerecord(&Player, Fileloc);      /* update a final time */
366     altercoordinates(0.0, 0.0, A_NEAR); /* move away from battle site */
367     Player.p_energy = Shield;           /* set energy to actual value */
368     Player.p_tampered = T_OFF;          /* clear p_tampered */
369
370     more(Lines);                        /* pause */
371
372     move(4, 0);
373     clrtobot();                         /* clear bottom area of screen */
374
375     if (Player.p_energy < 0.0)
376         /* we are dead */
377         death("Interterminal battle");
378 }
379 /*\f*/
380 /************************************************************************
381 /
382 / FUNCTION NAME: myturn()
383 /
384 / FUNCTION: process players action against foe in battle
385 /
386 / AUTHOR: E. A. Estes, 2/7/86
387 /
388 / ARGUMENTS: none
389 /
390 / RETURN VALUE: none
391 /
392 / MODULES CALLED: writerecord(), inputoption(), floor(), wmove(), drandom(),
393 /       waddstr(), wrefresh(), mvprintw(), wclrtoeol(), wclrtobot()
394 /
395 / GLOBAL INPUTS: Lines, Other, Player, *stdscr, Fileloc, Luckout,
396 /       *Enemyname
397 /
398 / GLOBAL OUTPUTS: Foestrikes, Lines, Player, Luckout
399 /
400 / DESCRIPTION:
401 /       Take action action against foe, and decide who is master
402 /       for next iteration.
403 /
404 *************************************************************************/
405
406 void
407 myturn(void)
408 {
409 double  dtemp;          /* for temporary calculations */
410 int     ch;             /* input */
411
412     mvaddstr(7, 0, "1:Fight  2:Run Away!  3:Power Blast  ");
413     if (Luckout)
414         clrtoeol();
415     else
416         addstr("4:Luckout  ");
417
418     ch = inputoption();
419     move(Lines = 8, 0);
420     clrtobot();
421
422     switch (ch)
423         {
424         default:        /* fight */
425             dtemp = ROLL(2.0, Player.p_might);
426 HIT:
427             mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, dtemp);
428             Player.p_sin += 0.5;
429             Player.p_1scratch += dtemp;
430             Player.p_istat = I_OFF;
431             break;
432
433         case '2':       /* run away */
434             Player.p_1scratch -= 1.0;   /* change this to indicate action */
435             if (drandom() > 0.25)
436                 {
437                 mvaddstr(Lines++, 0, "You got away!");
438                 Player.p_istat = I_RAN;
439                 }
440             else
441                 {
442                 mvprintw(Lines++, 0, "%s is still after you!", Enemyname);
443                 Player.p_istat = I_STUCK;
444                 }
445             break;
446
447         case '3':       /* power blast */
448             dtemp = MIN(Player.p_mana, Player.p_level * 5.0);
449             Player.p_mana -= dtemp;
450             dtemp *= (drandom() + 0.5) * Player.p_magiclvl * 0.2 + 2.0;
451             mvprintw(Lines++, 0, "You blasted %s !", Enemyname);
452             goto HIT;
453
454         case '4':       /* luckout */
455             if (Luckout || drandom() > 0.1)
456                 {
457                 if (Luckout)
458                     mvaddstr(Lines++, 0, "You already tried that!");
459                 else
460                     {
461                     mvaddstr(Lines++, 0, "Not this time . . .");
462                     Luckout = TRUE;
463                     }
464
465                 Player.p_1scratch -= 1.0;
466                 Player.p_istat = I_BLEWIT;
467                 }
468             else
469                 {
470                 mvaddstr(Lines++, 0, "You just lucked out!");
471                 Player.p_1scratch = Other.p_energy * 1.1;
472                 }
473             break;
474         }
475
476     refresh();
477     Player.p_1scratch = floor(Player.p_1scratch);       /* clean up any mess */
478
479     if (Player.p_1scratch > Other.p_energy)
480         Player.p_istat = I_KILLED;
481     else if (drandom() * Player.p_speed < drandom() * Other.p_speed)
482         /* relinquish control */
483         {
484         ++Player.p_tampered;
485         Foestrikes = TRUE;
486         }
487
488     writerecord(&Player, Fileloc);                      /* let foe know what we did */
489 }
490 /*\f*/
491 /************************************************************************
492 /
493 / FUNCTION NAME: checktampered()
494 /
495 / FUNCTION: check if current player has been tampered with
496 /
497 / AUTHOR: E. A. Estes, 12/4/85
498 /
499 / ARGUMENTS: none
500 /
501 / RETURN VALUE: none
502 /
503 / MODULES CALLED: readrecord(), fread(), fseek(), tampered(), writevoid()
504 /
505 / GLOBAL INPUTS: *Energyvoidfp, Other, Player, Fileloc, Enrgyvoid
506 /
507 / GLOBAL OUTPUTS: Enrgyvoid
508 /
509 / DESCRIPTION:
510 /       Check for energy voids, holy grail, and tampering by other
511 /       players.
512 /
513 *************************************************************************/
514
515 void
516 checktampered(void)
517 {
518 long    loc = 0L;               /* location in energy void file */
519
520     /* first check for energy voids */
521     fseek(Energyvoidfp, 0L, 0);
522     while (fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1)
523         if (Enrgyvoid.ev_active
524             && Enrgyvoid.ev_x == Player.p_x
525             && Enrgyvoid.ev_y == Player.p_y)
526             /* sitting on one */
527             {
528             if (loc > 0L)
529                 /* not the holy grail; inactivate energy void */
530                 {
531                 Enrgyvoid.ev_active = FALSE;
532                 writevoid(&Enrgyvoid, loc);
533                 tampered(T_NRGVOID, 0.0, 0.0);
534                 }
535             else if (Player.p_status != S_CLOAKED)
536                 /* holy grail */
537                 tampered(T_GRAIL, 0.0, 0.0);
538             break;
539             }
540         else
541             loc += SZ_VOIDSTRUCT;
542
543     /* now check for other things */
544     readrecord(&Other, Fileloc);
545     if (Other.p_tampered != T_OFF)
546         tampered(Other.p_tampered, Other.p_1scratch, Other.p_2scratch);
547 }
548 /*\f*/
549 /************************************************************************
550 /
551 / FUNCTION NAME: tampered()
552 /
553 / FUNCTION: take care of tampering by other players
554 /
555 / AUTHOR: E. A. Estes, 12/4/85
556 /
557 / ARGUMENTS:
558 /       int what - what type of tampering
559 /       double arg1, arg2 - rest of tampering info
560 /
561 / RETURN VALUE: none
562 /
563 / MODULES CALLED: writerecord(), more(), fread(), death(), fseek(), sleep(),
564 /       floor(), wmove(), waddch(), drandom(), printw(), altercoordinates(),
565 /       waddstr(), wrefresh(), encounter(), writevoid()
566 /
567 / GLOBAL INPUTS: Other, Player, *stdscr, Enrgyvoid, *Playersfp
568 /
569 / GLOBAL OUTPUTS: Other, Player, Changed, Enrgyvoid
570 /
571 / DESCRIPTION:
572 /       Take care of energy voids, holy grail, decree and intervention
573 /       action on current player.
574 /
575 *************************************************************************/
576
577 void
578 tampered(int what, double arg1, double arg2)
579 {
580 long    loc;                    /* location in file of other players */
581
582     Changed = TRUE;
583     move(4,0);
584
585     Player.p_tampered = T_OFF;  /* no longer tampered with */
586
587     switch (what)
588         {
589         case T_NRGVOID:
590             addstr("You've hit an energy void !\n");
591             Player.p_mana /= 3.0;
592             Player.p_energy /= 2.0;
593             Player.p_gold = floor(Player.p_gold/1.25) + 0.1;
594             altercoordinates(0.0, 0.0, A_NEAR);
595             break;
596
597         case T_TRANSPORT:
598             addstr("The king transported you !  ");
599             if (Player.p_charms > 0)
600                 {
601                 addstr("But your charm saved you. . .\n");
602                 --Player.p_charms;
603                 }
604             else
605                 {
606                 altercoordinates(0.0, 0.0, A_FAR);
607                 addch('\n');
608                 }
609             break;
610
611         case T_BESTOW:
612             printw("The king has bestowed %.0f gold pieces on you !\n", arg1);
613             Player.p_gold += arg1;
614             break;
615
616         case T_CURSED:
617             addstr("You've been cursed !  ");
618             if (Player.p_blessing)
619                 {
620                 addstr("But your blessing saved you. . .\n");
621                 Player.p_blessing = FALSE;
622                 }
623             else
624                 {
625                 addch('\n');
626                 Player.p_poison += 2.0;
627                 Player.p_energy = 10.0;
628                 Player.p_maxenergy  *= 0.95;
629                 Player.p_status = S_PLAYING;    /* no longer cloaked */
630                 }
631             break;
632
633         case T_VAPORIZED:
634             addstr("You have been vaporized!\n");
635             more(7);
636             death("Vaporization");
637             break;
638
639         case T_MONSTER:
640             addstr("The Valar zapped you with a monster!\n");
641             more(7);
642             encounter((int) arg1);
643             return;
644
645         case T_BLESSED:
646             addstr("The Valar has blessed you!\n");
647             Player.p_energy = (Player.p_maxenergy *= 1.05) + Player.p_shield;
648             Player.p_mana += 500.0;
649             Player.p_strength += 0.5;
650             Player.p_brains += 0.5;
651             Player.p_magiclvl += 0.5;
652             Player.p_poison = MIN(0.5, Player.p_poison);
653             break;
654
655         case T_RELOCATE:
656             addstr("You've been relocated. . .\n");
657             altercoordinates(arg1, arg2, A_FORCED);
658             break;
659
660         case T_HEAL:
661             addstr("You've been healed!\n");
662             Player.p_poison -=  0.25;
663             Player.p_energy = Player.p_maxenergy + Player.p_shield;
664             break;
665
666         case T_EXVALAR:
667             addstr("You are no longer Valar!\n");
668             Player.p_specialtype = SC_COUNCIL;
669             break;
670
671         case T_GRAIL:
672             addstr("You have found The Holy Grail!!\n");
673             if (Player.p_specialtype < SC_COUNCIL)
674                 /* must be council of wise to behold grail */
675                 {
676                 addstr("However, you are not experienced enough to behold it.\n");
677                 Player.p_sin *= Player.p_sin;
678                 Player.p_mana +=  1000;
679                 }
680             else if (Player.p_specialtype == SC_VALAR
681                 || Player.p_specialtype == SC_EXVALAR)
682                 {
683                 addstr("You have made it to the position of Valar once already.\n");
684                 addstr("The Grail is of no more use to you now.\n");
685                 }
686             else
687                 {
688                 addstr("It is now time to see if you are worthy to behold it. . .\n");
689                 refresh();
690                 sleep(4);
691
692                 if (drandom() / 2.0 < Player.p_sin)
693                     {
694                     addstr("You have failed!\n");
695                     Player.p_strength =
696                     Player.p_mana =
697                     Player.p_energy =
698                     Player.p_maxenergy =
699                     Player.p_magiclvl =
700                     Player.p_brains =
701                     Player.p_experience =
702                     Player.p_quickness = 1.0;
703
704                     altercoordinates(1.0, 1.0, A_FORCED);
705                     Player.p_level = 0.0;
706                     }
707                 else
708                     {
709                     addstr("You made to position of Valar!\n");
710                     Player.p_specialtype = SC_VALAR;
711                     Player.p_lives = 5;
712                     fseek(Playersfp, 0L, 0);
713                     loc = 0L;
714                     while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
715                         /* search for existing valar */
716                         if (Other.p_specialtype == SC_VALAR
717                             && Other.p_status != S_NOTUSED)
718                             /* found old valar */
719                             {
720                             Other.p_tampered = T_EXVALAR;
721                             writerecord(&Other, loc);
722                             break;
723                             }
724                         else
725                             loc += SZ_PLAYERSTRUCT;
726                     }
727                 }
728
729             /* move grail to new location */
730             Enrgyvoid.ev_active = TRUE;
731             Enrgyvoid.ev_x = ROLL(-1.0e6, 2.0e6);
732             Enrgyvoid.ev_y = ROLL(-1.0e6, 2.0e6);
733             writevoid(&Enrgyvoid, 0L);
734             break;
735         }
736     refresh();
737     sleep(2);
738 }
739 /*\f*/
740 /************************************************************************
741 /
742 / FUNCTION NAME: userlist()
743 /
744 / FUNCTION: print list of players and locations
745 /
746 / AUTHOR: E. A. Estes, 2/28/86
747 /
748 / ARGUMENTS:
749 /       bool ingameflag - set if called while playing
750 /
751 / RETURN VALUE: none
752 /
753 / MODULES CALLED: descrstatus(), descrlocation(), more(), fread(), fseek(),
754 /       floor(), wmove(), printw(), waddstr(), distance(), wrefresh(),
755 /       descrtype(), wclrtobot()
756 /
757 / GLOBAL INPUTS: LINES, Other, Circle, Wizard, Player, *stdscr, *Playersfp
758 /
759 / GLOBAL OUTPUTS: none
760 /
761 / DESCRIPTION:
762 /       We can only see the coordinate of those closer to the origin
763 /       from us.
764 /       Kings and council of the wise can see and can be seen by everyone.
765 /       Palantirs are good for seeing everyone; and the valar can use
766 /       one to see through a 'cloak' spell.
767 /       The valar has no coordinates, and is completely invisible if
768 /       cloaked.
769 /
770 *************************************************************************/
771
772 void
773 userlist(bool ingameflag)
774 {
775 int     numusers = 0;   /* number of users on file */
776
777     if (ingameflag && Player.p_blindness)
778         {
779         mvaddstr(8, 0, "You cannot see anyone.\n");
780         return;
781         }
782
783     fseek(Playersfp, 0L, 0);
784     mvaddstr(8, 0,
785         "Name                         X         Y    Lvl Type Login    Status\n");
786
787     while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
788         {
789         if (Other.p_status == S_NOTUSED
790             /* record is unused */
791             || (Other.p_specialtype == SC_VALAR && Other.p_status == S_CLOAKED))
792             /* cloaked valar */
793             {
794             if (!Wizard)
795                 /* wizard can see everything on file */
796                 continue;
797             }
798
799             ++numusers;
800
801             if (ingameflag &&
802                 /* must be playing for the rest of these conditions */
803                 (Player.p_specialtype >= SC_KING
804                 /* kings and higher can see others */
805                 || Other.p_specialtype >= SC_KING
806                 /* kings and higher can be seen by others */
807                 || Circle >= CIRCLE(Other.p_x, Other.p_y)
808                 /* those nearer the origin can be seen */
809                 || Player.p_palantir)
810                 /* palantir enables one to see others */
811                 && (Other.p_status != S_CLOAKED
812                     || (Player.p_specialtype == SC_VALAR && Player.p_palantir))
813                 /* not cloaked; valar can see through cloak with a palantir */
814                 && Other.p_specialtype != SC_VALAR)
815                 /* not a valar */
816                 /* coordinates should be printed */
817                 printw("%-20s  %8.0f  %8.0f ",
818                     Other.p_name, Other.p_x, Other.p_y);
819             else
820                 /* cannot see player's coordinates */
821                 printw("%-20s %19.19s ",
822                     Other.p_name, descrlocation(&Other, TRUE));
823
824         printw("%6.0f %s  %-9.9s%s\n", Other.p_level, descrtype(&Other, TRUE),
825             Other.p_login, descrstatus(&Other));
826
827         if ((numusers % (LINES - 10)) == 0)
828             {
829             more(LINES - 1);
830             move(9, 0);
831             clrtobot();
832             }
833         }
834
835     printw("Total players on file = %d\n", numusers);
836     refresh();
837 }
838 /*\f*/
839 /************************************************************************
840 /
841 / FUNCTION NAME: throneroom()
842 /
843 / FUNCTION: king stuff upon entering throne
844 /
845 / AUTHOR: E. A. Estes, 12/16/85
846 /
847 / ARGUMENTS: none
848 /
849 / RETURN VALUE: none
850 /
851 / MODULES CALLED: writerecord(), fread(), fseek(), fopen(), wmove(), fclose(),
852 /       fwrite(), altercoordinates(), waddstr(), fprintf()
853 /
854 / GLOBAL INPUTS: *Energyvoidfp, Other, Player, *stdscr,
855 /       Enrgyvoid, *Playersfp
856 /
857 / GLOBAL OUTPUTS: Other, Player, Changed
858 /
859 / DESCRIPTION:
860 /       If player is not already king, make him/her so if the old king
861 /       is not playing.
862 /       Clear energy voids with new king.
863 /       Print 'decree' prompt.
864 /
865 *************************************************************************/
866
867 void
868 throneroom(void)
869 {
870 FILE    *fp;                    /* to clear energy voids */
871 long    loc = 0L;               /* location of old king in player file */
872
873     if (Player.p_specialtype < SC_KING)
874         /* not already king -- assumes crown */
875         {
876         fseek(Playersfp, 0L, 0);
877         while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
878             if (Other.p_specialtype == SC_KING && Other.p_status != S_NOTUSED)
879                 /* found old king */
880                 {
881                 if (Other.p_status != S_OFF)
882                     /* old king is playing */
883                     {
884                     mvaddstr( 4, 0, "The king is playing, so you cannot steal his throne\n");
885                     altercoordinates(0.0, 0.0, A_NEAR);
886                     move(6, 0);
887                     return;
888                     }
889                 else
890                     /* old king is not playing - remove him/her */
891                     {
892                     Other.p_specialtype = SC_NONE;
893                     if (Other.p_crowns)
894                         --Other.p_crowns;
895                     writerecord(&Other, loc);
896                     break;
897                     }
898                 }
899             else
900                 loc += SZ_PLAYERSTRUCT;
901
902         /* make player new king */
903         Changed = TRUE;
904         Player.p_specialtype = SC_KING;
905         mvaddstr(4, 0, "You have become king!\n");
906
907         /* let everyone else know */
908         fp = fopen(_PATH_MESS, "w");
909         fprintf(fp, "All hail the new king!");
910         fclose(fp);
911
912         /* clear all energy voids; retain location of holy grail */
913         fseek(Energyvoidfp, 0L, 0);
914         fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp);
915         fp = fopen(_PATH_VOID, "w");
916         fwrite((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, fp);
917         fclose(fp);
918         }
919
920     mvaddstr(6, 0, "0:Decree  ");
921 }
922 /*\f*/
923 /************************************************************************
924 /
925 / FUNCTION NAME: dotampered()
926 /
927 / FUNCTION: king and valar special options
928 /
929 / AUTHOR: E. A. Estes, 2/28/86
930 /
931 / ARGUMENTS: none
932 /
933 / RETURN VALUE: none
934 /
935 / MODULES CALLED: writerecord(), truncstring(), fread(), fseek(), fopen(),
936 /       floor(), wmove(), drandom(), fclose(), fwrite(), sscanf(), strcmp(),
937 /       infloat(), waddstr(), findname(), distance(), userlist(), mvprintw(),
938 /       allocvoid(), getanswer(), getstring(), wclrtoeol(), writevoid()
939 /
940 / GLOBAL INPUTS: *Energyvoidfp, Other, Illcmd[], Wizard, Player, *stdscr,
941 /       Databuf[], Enrgyvoid
942 /
943 / GLOBAL OUTPUTS: Other, Player, Enrgyvoid
944 /
945 / DESCRIPTION:
946 /       Tamper with other players.  Handle king/valar specific options.
947 /
948 *************************************************************************/
949
950 void
951 dotampered(void)
952 {
953 short   tamper;                 /* value for tampering with other players */
954 const char      *option;                        /* pointer to option description */
955 double  temp1 = 0.0, temp2 = 0.0;       /* other tampering values */
956 int     ch;                             /* input */
957 long    loc;                            /* location in energy void file */
958 FILE    *fp;                            /* for opening gold file */
959
960     move(6, 0);
961     clrtoeol();
962     if (Player.p_specialtype < SC_COUNCIL && !Wizard)
963         /* king options */
964         {
965         addstr("1:Transport  2:Curse  3:Energy Void  4:Bestow  5:Collect Taxes  ");
966
967         ch = getanswer(" ", TRUE);
968         move(6, 0);
969         clrtoeol();
970         move(4, 0);
971         switch (ch)
972             {
973             case '1':   /* transport someone */
974                 tamper = T_TRANSPORT;
975                 option = "transport";
976                 break;
977
978             case '2':   /* curse another */
979                 tamper = T_CURSED;
980                 option = "curse";
981                 break;
982
983             case '3':   /* create energy void */
984                 if ((loc = allocvoid()) > 20L * (long)SZ_VOIDSTRUCT)
985                     /* can only have 20 void active at once */
986                     mvaddstr(5, 0, "Sorry, void creation limit reached.\n");
987                 else
988                     {
989                     addstr("Enter the X Y coordinates of void ? ");
990                     getstring(Databuf, SZ_DATABUF);
991                     sscanf(Databuf, "%lf %lf", &temp1, &temp2);
992                     Enrgyvoid.ev_x = floor(temp1);
993                     Enrgyvoid.ev_y = floor(temp2);
994                     Enrgyvoid.ev_active = TRUE;
995                     writevoid(&Enrgyvoid, loc);
996                     mvaddstr(5, 0, "It is done.\n");
997                     }
998                 return;
999
1000             case '4':   /* bestow gold to subject */
1001                 tamper = T_BESTOW;
1002                 addstr("How much gold to bestow ? ");
1003                 temp1 = infloat();
1004                 if (temp1 > Player.p_gold || temp1 < 0)
1005                     {
1006                     mvaddstr(5, 0, "You don't have that !\n");
1007                     return;
1008                     }
1009
1010                 /* adjust gold after we are sure it will be given to someone */
1011                 option = "give gold to";
1012                 break;
1013
1014             case '5':   /* collect accumulated taxes */
1015                 if ((fp = fopen(_PATH_GOLD, "r+")) != NULL)
1016                     /* collect taxes */
1017                     {
1018                     fread((char *) &temp1, sizeof(double), 1, fp);
1019                     fseek(fp, 0L, 0);
1020                     /* clear out value */
1021                     temp2 = 0.0;
1022                     fwrite((char *) &temp2, sizeof(double), 1, fp);
1023                     fclose(fp);
1024                     }
1025
1026                 mvprintw(4, 0, "You have collected %.0f in gold.\n", temp1);
1027                 Player.p_gold += floor(temp1);
1028                 return;
1029
1030             default:
1031                 return;
1032             }
1033         /* end of king options */
1034         }
1035     else
1036         /* council of wise, valar, wizard options */
1037         {
1038         addstr("1:Heal  ");
1039         if (Player.p_palantir || Wizard)
1040             addstr("2:Seek Grail  ");
1041         if (Player.p_specialtype == SC_VALAR || Wizard)
1042             addstr("3:Throw Monster  4:Relocate  5:Bless  ");
1043         if (Wizard)
1044             addstr("6:Vaporize  ");
1045
1046         ch = getanswer(" ", TRUE);
1047         if (!Wizard)
1048             {
1049             if (ch > '2' && Player.p_specialtype != SC_VALAR)
1050                 {
1051                 ILLCMD();
1052                 return;
1053                 }
1054
1055             if (Player.p_mana < MM_INTERVENE)
1056                 {
1057                 mvaddstr(5, 0, "No mana left.\n");
1058                 return;
1059                 }
1060             else
1061                 Player.p_mana -= MM_INTERVENE;
1062             }
1063
1064         switch (ch)
1065             {
1066             case '1':   /* heal another */
1067                 tamper = T_HEAL;
1068                 option = "heal";
1069                 break;
1070
1071             case '2':   /* seek grail */
1072                 if (Player.p_palantir)
1073                     /* need a palantir to seek */
1074                     {
1075                     fseek(Energyvoidfp, 0L, 0);
1076                     fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp);
1077                     temp1 = distance(Player.p_x, Enrgyvoid.ev_x, Player.p_y, Enrgyvoid.ev_y);
1078                     temp1 += ROLL(-temp1 / 10.0, temp1 / 5.0);  /* add some error */
1079                     mvprintw(5, 0, "The palantir says the Grail is about %.0f away.\n", temp1);
1080                     }
1081                 else
1082                     /* no palantir */
1083                     mvaddstr(5, 0, "You need a palantir to seek the Grail.\n");
1084                 return;
1085
1086             case '3':   /* lob monster at someone */
1087                 mvaddstr(4, 0, "Which monster [0-99] ? ");
1088                 temp1 = infloat();
1089                 temp1 = MAX(0.0, MIN(99.0, temp1));
1090                 tamper = T_MONSTER;
1091                 option = "throw a monster at";
1092                 break;
1093
1094             case '4':   /* move another player */
1095                 mvaddstr(4, 0, "New X Y coordinates ? ");
1096                 getstring(Databuf, SZ_DATABUF);
1097                 sscanf(Databuf, "%lf %lf", &temp1, &temp2);
1098                 tamper = T_RELOCATE;
1099                 option = "relocate";
1100                 break;
1101
1102             case '5':   /* bless a player */
1103                 tamper = T_BLESSED;
1104                 option = "bless";
1105                 break;
1106
1107             case '6':   /* kill off a player */
1108                 if (Wizard)
1109                     {
1110                     tamper = T_VAPORIZED;
1111                     option = "vaporize";
1112                     break;
1113                     }
1114                 else
1115                     return;
1116
1117             default:
1118                 return;
1119             }
1120
1121         /* adjust age after we are sure intervention will be done */
1122         /* end of valar, etc. options */
1123         }
1124
1125     for (;;)
1126         /* prompt for player to affect */
1127         {
1128         mvprintw(4, 0, "Who do you want to %s ? ", option);
1129         getstring(Databuf, SZ_DATABUF);
1130         truncstring(Databuf);
1131
1132         if (Databuf[0] == '\0')
1133             userlist(TRUE);
1134         else
1135             break;
1136         }
1137
1138     if (strcmp(Player.p_name, Databuf) != 0)
1139         /* name other than self */
1140         {
1141         if ((loc = findname(Databuf, &Other)) >= 0L)
1142             {
1143             if (Other.p_tampered != T_OFF)
1144                 {
1145                 mvaddstr(5, 0, "That person has something pending already.\n");
1146                 return;
1147                 }
1148             else
1149                 {
1150                 if (tamper == T_RELOCATE
1151                     && CIRCLE(temp1, temp2) < CIRCLE(Other.p_x, Other.p_y)
1152                     && !Wizard)
1153                     mvaddstr(5, 0, "Cannot move someone closer to the Lord's Chamber.\n");
1154                 else
1155                     {
1156                     if (tamper == T_BESTOW) Player.p_gold -= floor(temp1);
1157                     if (!Wizard && (tamper == T_HEAL || tamper == T_MONSTER ||
1158                         tamper == T_RELOCATE || tamper == T_BLESSED))
1159                                 Player.p_age += N_AGE;  /* age penalty */
1160                     Other.p_tampered = tamper;
1161                     Other.p_1scratch = floor(temp1);
1162                     Other.p_2scratch = floor(temp2);
1163                     writerecord(&Other, loc);
1164                     mvaddstr(5, 0, "It is done.\n");
1165                     }
1166                 return;
1167                 }
1168             }
1169         else
1170             /* player not found */
1171             mvaddstr(5, 0, "There is no one by that name.\n");
1172         }
1173     else
1174         /* self */
1175         mvaddstr(5, 0, "You may not do it to yourself!\n");
1176 }
1177 /*\f*/
1178 /************************************************************************
1179 /
1180 / FUNCTION NAME: writevoid()
1181 /
1182 / FUNCTION: update energy void entry in energy void file
1183 /
1184 / AUTHOR: E. A. Estes, 12/4/85
1185 /
1186 / ARGUMENTS:
1187 /       struct energyvoid *vp - pointer to structure to write to file
1188 /       long loc - location in file to update
1189 /
1190 / RETURN VALUE: none
1191 /
1192 / MODULES CALLED: fseek(), fwrite(), fflush()
1193 /
1194 / GLOBAL INPUTS: *Energyvoidfp
1195 /
1196 / GLOBAL OUTPUTS: none
1197 /
1198 / DESCRIPTION:
1199 /       Write out energy void structure at specified location.
1200 /
1201 *************************************************************************/
1202
1203 void
1204 writevoid(struct energyvoid *vp, long loc)
1205 {
1206
1207     fseek(Energyvoidfp, loc, 0);
1208     fwrite((char *) vp, SZ_VOIDSTRUCT, 1, Energyvoidfp);
1209     fflush(Energyvoidfp);
1210     fseek(Energyvoidfp, 0L, 0);
1211 }
1212 /*\f*/
1213 /************************************************************************
1214 /
1215 / FUNCTION NAME: allocvoid()
1216 /
1217 / FUNCTION: allocate space for a new energy void
1218 /
1219 / AUTHOR: E. A. Estes, 12/4/85
1220 /
1221 / ARGUMENTS: none
1222 /
1223 / RETURN VALUE: location of new energy void space
1224 /
1225 / MODULES CALLED: fread(), fseek()
1226 /
1227 / GLOBAL INPUTS: *Energyvoidfp, Enrgyvoid
1228 /
1229 / GLOBAL OUTPUTS: none
1230 /
1231 / DESCRIPTION:
1232 /       Search energy void file for an inactive entry and return its
1233 /       location.
1234 /       If no inactive ones are found, return one more than last location.
1235 /
1236 *************************************************************************/
1237
1238 size_t
1239 allocvoid(void)
1240 {
1241 size_t  loc = 0;                /* location of new energy void */
1242
1243     fseek(Energyvoidfp, 0L, 0);
1244     while (fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1)
1245         if (Enrgyvoid.ev_active)
1246             loc += SZ_VOIDSTRUCT;
1247         else
1248             break;
1249
1250     return(loc);
1251 }