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