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