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