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