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