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