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