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