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