/*	$OpenBSD: interplayer.c,v 1.4 2000/06/29 07:39:44 pjanzen Exp $	*/
/*	$NetBSD: interplayer.c,v 1.2 1995/03/24 03:58:47 cgd Exp $	*/

/*
 * interplayer.c - player to player routines for Phantasia
 */

#include "include.h"

/************************************************************************
/
/ FUNCTION NAME: checkbattle()
/
/ FUNCTION: check to see if current player should battle another
/
/ AUTHOR: E. A. Estes, 12/4/85
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: battleplayer(), fread(), fseek()
/
/ GLOBAL INPUTS: Other, Users, Player, Fileloc, *Playersfp
/
/ GLOBAL OUTPUTS: Users
/
/ DESCRIPTION:
/	Seach player file for a foe at the same coordinates as the
/	current player.
/	Also update user count.
/
*************************************************************************/

void
checkbattle()
{
	long    foeloc = 0L;	/* location in file of person to fight */

	Users = 0;
	fseek(Playersfp, 0L, SEEK_SET);

	while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) {
		if (Other.p_status != S_OFF
		    && Other.p_status != S_NOTUSED
		    && Other.p_status != S_HUNGUP
		    && (Other.p_status != S_CLOAKED || Other.p_specialtype != SC_VALAR))
			/* player is on and not a cloaked valar */
		{
			++Users;

			if (Player.p_x == Other.p_x
			    && Player.p_y == Other.p_y
			/* same coordinates */
			    && foeloc != Fileloc
			/* not self */
			    && Player.p_status == S_PLAYING
			    && (Other.p_status == S_PLAYING || Other.p_status == S_INBATTLE)
			/* both are playing */
			    && Other.p_specialtype != SC_VALAR
			    && Player.p_specialtype != SC_VALAR)
				/* neither is valar */
			{
				battleplayer(foeloc);
				return;
			}
		}
		foeloc += SZ_PLAYERSTRUCT;
	}
}
/**/
/************************************************************************
/
/ FUNCTION NAME: battleplayer()
/
/ FUNCTION: inter-terminal battle with another player
/
/ AUTHOR: E. A. Estes, 2/15/86
/
/ ARGUMENTS:
/	long foeplace - location in player file of person to battle
/
/ RETURN VALUE: none
/
/ MODULES CALLED: readrecord(), readmessage(), writerecord(), collecttaxes(), 
/	displaystats(), fabs(), more(), death(), sleep(), wmove(), waddch(), printw(), 
/	myturn(), altercoordinates(), waddstr(), wrefresh(), mvprintw(), 
/	getanswer(), wclrtoeol(), wclrtobot()
/
/ GLOBAL INPUTS: Foestrikes, LINES, Lines, Other, Shield, Player, *stdscr, 
/	Fileloc, *Enemyname
/
/ GLOBAL OUTPUTS: Foestrikes, Lines, Shield, Player, Luckout, *Enemyname
/
/ DESCRIPTION:
/	Inter-terminal battle is a very fragile and slightly klugy thing.
/	At any time, one player is master and the other is slave.
/	We pick who is master first by speed and level.  After that,
/	the slave waits for the master to relinquish its turn, and
/	the slave becomes master, and so on.
/
/	The items in the player structure which control the handshake are:
/	    p_tampered:
/		master increments this to relinquish control
/	    p_istat:
/		master sets this to specify particular action
/	    p_1scratch:
/		set to total damage inflicted so far; changes to indicate action
/
*************************************************************************/

void
battleplayer(foeplace)
	long    foeplace;
{
	double  dtemp;		/* for temporary calculations */
	double  oldhits = 0.0;	/* previous damage inflicted by foe */
	int     loop;		/* for timing out */
	int     ch;		/* input */
	short   oldtampered;	/* old value of foe's p_tampered */

	Lines = 8;
	Luckout = FALSE;
	mvaddstr(4, 0, "Preparing for battle!\n");
	refresh();

#ifdef SYS5
	flushinp();
#endif

	/* set up variables, file, etc. */
	Player.p_status = S_INBATTLE;
	Shield = Player.p_energy;

	/* if p_tampered is not 0, someone else may try to change it (king,
	 * etc.) */
	Player.p_tampered = oldtampered = 1;
	Player.p_1scratch = 0.0;
	Player.p_istat = I_OFF;

	readrecord(&Other, foeplace);
	if (fabs(Player.p_level - Other.p_level) > 20.0)
		/* see if players are greatly mismatched */
	{
		dtemp = (Player.p_level - Other.p_level) / MAX(Player.p_level, Other.p_level);
		if (dtemp < -0.5)
			/* foe outweighs this one */
			Player.p_speed *= 2.0;
	}
	writerecord(&Player, Fileloc);	/* write out all our info */

	if (Player.p_blindness)
		Enemyname = "someone";
	else
		Enemyname = Other.p_name;

	mvprintw(6, 0, "You have encountered %s   Level: %.0f\n", Enemyname, Other.p_level);
	refresh();

	for (loop = 0; Other.p_status != S_INBATTLE && loop < 30; ++loop)
		/* wait for foe to respond */
	{
		readrecord(&Other, foeplace);
		sleep(1);
	}

	if (Other.p_status != S_INBATTLE)
		/* foe did not respond */
	{
		mvprintw(5, 0, "%s is not responding.\n", Enemyname);
		goto LEAVE;
	}
	/* else, we are ready to battle */

	move(4, 0);
	clrtoeol();

	/*
         * determine who is first master
         * if neither player is faster, check level
         * if neither level is greater, battle is not allowed
         * (this should never happen, but we have to handle it)
         */
	if (Player.p_speed > Other.p_speed)
		Foestrikes = FALSE;
	else if (Other.p_speed > Player.p_speed)
		Foestrikes = TRUE;
	else if (Player.p_level > Other.p_level)
		Foestrikes = FALSE;
	else if (Other.p_level > Player.p_level)
		Foestrikes = TRUE;
	else {
		/* no one is faster */
		printw("You can't fight %s yet.", Enemyname);
		goto LEAVE;
	}

	for (;;) {
		displaystats();
		readmessage();
		mvprintw(1, 26, "%20.0f", Shield);	/* overprint energy */

		if (!Foestrikes)
			/* take action against foe */
			myturn();
		else
			/* wait for foe to take action */
		{
			mvaddstr(4, 0, "Waiting...\n");
			clrtoeol();
			refresh();

			for (loop = 0; loop < 20; ++loop)
				/* wait for foe to act */
			{
				readrecord(&Other, foeplace);
				if (Other.p_1scratch != oldhits)
					/* p_1scratch changes to indicate
					 * action */
					break;
				else
					/* wait and try again */
				{
					sleep(1);
					addch('.');
					refresh();
				}
			}

			if (Other.p_1scratch == oldhits) {
				/* timeout */
				mvaddstr(22, 0, "Timeout: waiting for response.  Do you want to wait ? ");
				ch = getanswer("NY", FALSE);
				move(22, 0);
				clrtobot();
				if (ch == 'Y')
					continue;
				else
					break;
			} else
				/* foe took action */
			{
				switch (Other.p_istat) {
				case I_RAN:	/* foe ran away */
					mvprintw(Lines++, 0, "%s ran away!", Enemyname);
					break;

				case I_STUCK:	/* foe tried to run, but
						 * couldn't */
					mvprintw(Lines++, 0, "%s tried to run away.", Enemyname);
					break;

				case I_BLEWIT:	/* foe tried to luckout, but
						 * didn't */
					mvprintw(Lines++, 0, "%s tried to luckout!", Enemyname);
					break;

				default:
					dtemp = Other.p_1scratch - oldhits;
					mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, dtemp);
					Shield -= dtemp;
					break;
				}

				oldhits = Other.p_1scratch;	/* keep track of old
								 * hits */

				if (Other.p_tampered != oldtampered)
					/* p_tampered changes to relinquish
					 * turn */
				{
					oldtampered = Other.p_tampered;
					Foestrikes = FALSE;
				}
			}
		}

		/* decide what happens next */
		refresh();
		if (Lines > LINES - 2) {
			more(Lines);
			move(Lines = 8, 0);
			clrtobot();
		}
		if (Other.p_istat == I_KILLED || Shield < 0.0)
			/* we died */
		{
			Shield = -2.0;	/* insure this value is negative */
			break;
		}
		if (Player.p_istat == I_KILLED)
			/* we killed foe; award treasre */
		{
			mvprintw(Lines++, 0, "You killed %s!", Enemyname);
			Player.p_experience += Other.p_experience;
			Player.p_crowns += (Player.p_level < 1000.0) ? Other.p_crowns : 0;
			Player.p_amulets += Other.p_amulets;
			Player.p_charms += Other.p_charms;
			collecttaxes(Other.p_gold, Other.p_gems);
			Player.p_sword = MAX(Player.p_sword, Other.p_sword);
			Player.p_shield = MAX(Player.p_shield, Other.p_shield);
			Player.p_quksilver = MAX(Player.p_quksilver, Other.p_quksilver);
			if (Other.p_virgin && !Player.p_virgin) {
				mvaddstr(Lines++, 0, "You have rescued a virgin.  Will you be honorable ? ");
				if ((ch = getanswer("YN", FALSE)) == 'Y')
					Player.p_virgin = TRUE;
				else {
					++Player.p_sin;
					Player.p_experience += 8000.0;
				}
			}
			sleep(3);	/* give other person time to die */
			break;
		} else
			if (Player.p_istat == I_RAN || Other.p_istat == I_RAN)
				/* either player ran away */
				break;
	}

LEAVE:
	/* clean up things and leave */
	writerecord(&Player, Fileloc);	/* update a final time */
	altercoordinates(0.0, 0.0, A_NEAR);	/* move away from battle site */
	Player.p_energy = Shield;	/* set energy to actual value */
	Player.p_tampered = T_OFF;	/* clear p_tampered */

	more(Lines);		/* pause */

	move(4, 0);
	clrtobot();		/* clear bottom area of screen */

	if (Player.p_energy < 0.0)
		/* we are dead */
		death("Interterminal battle");
}
/**/
/************************************************************************
/
/ FUNCTION NAME: myturn()
/
/ FUNCTION: process players action against foe in battle
/
/ AUTHOR: E. A. Estes, 2/7/86
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: writerecord(), inputoption(), floor(), wmove(), drandom(), 
/	waddstr(), wrefresh(), mvprintw(), wclrtoeol(), wclrtobot()
/
/ GLOBAL INPUTS: Lines, Other, Player, *stdscr, Fileloc, Luckout, 
/	*Enemyname
/
/ GLOBAL OUTPUTS: Foestrikes, Lines, Player, Luckout
/
/ DESCRIPTION:
/	Take action action against foe, and decide who is master
/	for next iteration.
/
*************************************************************************/

void
myturn()
{
	double  dtemp;		/* for temporary calculations */
	int     ch;		/* input */

	mvaddstr(7, 0, "1:Fight  2:Run Away!  3:Power Blast  ");
	if (Luckout)
		clrtoeol();
	else
		addstr("4:Luckout  ");

	ch = inputoption();
	move(Lines = 8, 0);
	clrtobot();

	switch (ch) {
	default:		/* fight */
		dtemp = ROLL(2.0, Player.p_might);
HIT:
		mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, dtemp);
		Player.p_sin += 0.5;
		Player.p_1scratch += dtemp;
		Player.p_istat = I_OFF;
		break;

	case '2':		/* run away */
		Player.p_1scratch -= 1.0;	/* change this to indicate
						 * action */
		if (drandom() > 0.25) {
			mvaddstr(Lines++, 0, "You got away!");
			Player.p_istat = I_RAN;
		} else {
			mvprintw(Lines++, 0, "%s is still after you!", Enemyname);
			Player.p_istat = I_STUCK;
		}
		break;

	case '3':		/* power blast */
		dtemp = MIN(Player.p_mana, Player.p_level * 5.0);
		Player.p_mana -= dtemp;
		dtemp *= (drandom() + 0.5) * Player.p_magiclvl * 0.2 + 2.0;
		mvprintw(Lines++, 0, "You blasted %s !", Enemyname);
		goto HIT;

	case '4':		/* luckout */
		if (Luckout || drandom() > 0.1) {
			if (Luckout)
				mvaddstr(Lines++, 0, "You already tried that!");
			else {
				mvaddstr(Lines++, 0, "Not this time . . .");
				Luckout = TRUE;
			}

			Player.p_1scratch -= 1.0;
			Player.p_istat = I_BLEWIT;
		} else {
			mvaddstr(Lines++, 0, "You just lucked out!");
			Player.p_1scratch = Other.p_energy * 1.1;
		}
		break;
	}

	refresh();
	Player.p_1scratch = floor(Player.p_1scratch);	/* clean up any mess */

	if (Player.p_1scratch > Other.p_energy)
		Player.p_istat = I_KILLED;
	else
		if (drandom() * Player.p_speed < drandom() * Other.p_speed)
			/* relinquish control */
		{
			++Player.p_tampered;
			Foestrikes = TRUE;
		}
	writerecord(&Player, Fileloc);	/* let foe know what we did */
}
/**/
/************************************************************************
/
/ FUNCTION NAME: checktampered()
/
/ FUNCTION: check if current player has been tampered with
/
/ AUTHOR: E. A. Estes, 12/4/85
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: readrecord(), fread(), fseek(), tampered(), writevoid()
/
/ GLOBAL INPUTS: *Energyvoidfp, Other, Player, Fileloc, Enrgyvoid
/
/ GLOBAL OUTPUTS: Enrgyvoid
/
/ DESCRIPTION:
/	Check for energy voids, holy grail, and tampering by other
/	players.
/
*************************************************************************/

void
checktampered()
{
	long    loc = 0L;	/* location in energy void file */

	/* first check for energy voids */
	fseek(Energyvoidfp, 0L, SEEK_SET);
	while (fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1)
		if (Enrgyvoid.ev_active
		    && Enrgyvoid.ev_x == Player.p_x
		    && Enrgyvoid.ev_y == Player.p_y)
			/* sitting on one */
		{
			if (loc > 0L)
				/* not the holy grail; inactivate energy void */
			{
				Enrgyvoid.ev_active = FALSE;
				writevoid(&Enrgyvoid, loc);
				tampered(T_NRGVOID, 0.0, 0.0);
			} else
				if (Player.p_status != S_CLOAKED)
					/* holy grail */
					tampered(T_GRAIL, 0.0, 0.0);
			break;
		} else
			loc += SZ_VOIDSTRUCT;

	/* now check for other things */
	readrecord(&Other, Fileloc);
	if (Other.p_tampered != T_OFF)
		tampered(Other.p_tampered, Other.p_1scratch, Other.p_2scratch);
}
/**/
/************************************************************************
/
/ FUNCTION NAME: tampered()
/
/ FUNCTION: take care of tampering by other players
/
/ AUTHOR: E. A. Estes, 12/4/85
/
/ ARGUMENTS:
/	int what - what type of tampering
/	double arg1, arg2 - rest of tampering info
/
/ RETURN VALUE: none
/
/ MODULES CALLED: writerecord(), more(), fread(), death(), fseek(), sleep(), 
/	floor(), wmove(), waddch(), drandom(), printw(), altercoordinates(), 
/	waddstr(), wrefresh(), encounter(), writevoid()
/
/ GLOBAL INPUTS: Other, Player, *stdscr, Enrgyvoid, *Playersfp
/
/ GLOBAL OUTPUTS: Other, Player, Changed, Enrgyvoid
/
/ DESCRIPTION:
/	Take care of energy voids, holy grail, decree and intervention
/	action on current player.
/
*************************************************************************/

void
tampered(what, arg1, arg2)
	int     what;
	double  arg1;
	double  arg2;
{
	long    loc;		/* location in file of other players */

	Changed = TRUE;
	move(4, 0);

	Player.p_tampered = T_OFF;	/* no longer tampered with */

	switch (what) {
	case T_NRGVOID:
		addstr("You've hit an energy void !\n");
		Player.p_mana /= 3.0;
		Player.p_energy /= 2.0;
		Player.p_gold = floor(Player.p_gold / 1.25) + 0.1;
		altercoordinates(0.0, 0.0, A_NEAR);
		break;

	case T_TRANSPORT:
		addstr("The king transported you !  ");
		if (Player.p_charms > 0) {
			addstr("But your charm saved you. . .\n");
			--Player.p_charms;
		} else {
			altercoordinates(0.0, 0.0, A_FAR);
			addch('\n');
		}
		break;

	case T_BESTOW:
		printw("The king has bestowed %.0f gold pieces on you !\n", arg1);
		Player.p_gold += arg1;
		break;

	case T_CURSED:
		addstr("You've been cursed !  ");
		if (Player.p_blessing) {
			addstr("But your blessing saved you. . .\n");
			Player.p_blessing = FALSE;
		} else {
			addch('\n');
			Player.p_poison += 2.0;
			Player.p_energy = 10.0;
			Player.p_maxenergy *= 0.95;
			Player.p_status = S_PLAYING;	/* no longer cloaked */
		}
		break;

	case T_VAPORIZED:
		addstr("You have been vaporized!\n");
		more(7);
		death("Vaporization");
		break;

	case T_MONSTER:
		addstr("The Valar zapped you with a monster!\n");
		more(7);
		encounter((int) arg1);
		return;

	case T_BLESSED:
		addstr("The Valar has blessed you!\n");
		Player.p_energy = (Player.p_maxenergy *= 1.05) + Player.p_shield;
		Player.p_mana += 500.0;
		Player.p_strength += 0.5;
		Player.p_brains += 0.5;
		Player.p_magiclvl += 0.5;
		Player.p_poison = MIN(0.5, Player.p_poison);
		break;

	case T_RELOCATE:
		addstr("You've been relocated. . .\n");
		altercoordinates(arg1, arg2, A_FORCED);
		break;

	case T_HEAL:
		addstr("You've been healed!\n");
		Player.p_poison -= 0.25;
		Player.p_energy = Player.p_maxenergy + Player.p_shield;
		break;

	case T_EXVALAR:
		addstr("You are no longer Valar!\n");
		Player.p_specialtype = SC_COUNCIL;
		break;

	case T_GRAIL:
		addstr("You have found The Holy Grail!!\n");
		if (Player.p_specialtype < SC_COUNCIL)
			/* must be council of wise to behold grail */
		{
			addstr("However, you are not experienced enough to behold it.\n");
			Player.p_sin *= Player.p_sin;
			Player.p_mana += 1000;
		} else
			if (Player.p_specialtype == SC_VALAR
			    || Player.p_specialtype == SC_EXVALAR) {
				addstr("You have made it to the position of Valar once already.\n");
				addstr("The Grail is of no more use to you now.\n");
			} else {
				addstr("It is now time to see if you are worthy to behold it. . .\n");
				refresh();
				sleep(4);

				if (drandom() / 2.0 < Player.p_sin) {
					addstr("You have failed!\n");
					Player.p_strength =
					    Player.p_mana =
					    Player.p_energy =
					    Player.p_maxenergy =
					    Player.p_magiclvl =
					    Player.p_brains =
					    Player.p_experience =
					    Player.p_quickness = 1.0;

					altercoordinates(1.0, 1.0, A_FORCED);
					Player.p_level = 0.0;
				} else {
					addstr("You made to position of Valar!\n");
					Player.p_specialtype = SC_VALAR;
					Player.p_lives = 5;
					fseek(Playersfp, 0L, SEEK_SET);
					loc = 0L;
					while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
						/* search for existing valar */
						if (Other.p_specialtype == SC_VALAR
						    && Other.p_status != S_NOTUSED)
							/* found old valar */
						{
							Other.p_tampered = T_EXVALAR;
							writerecord(&Other, loc);
							break;
						} else
							loc += SZ_PLAYERSTRUCT;
				}
			}

		/* move grail to new location */
		Enrgyvoid.ev_active = TRUE;
		Enrgyvoid.ev_x = ROLL(-1.0e6, 2.0e6);
		Enrgyvoid.ev_y = ROLL(-1.0e6, 2.0e6);
		writevoid(&Enrgyvoid, 0L);
		break;
	}
	refresh();
	sleep(2);
}
/**/
/************************************************************************
/
/ FUNCTION NAME: userlist()
/
/ FUNCTION: print list of players and locations
/
/ AUTHOR: E. A. Estes, 2/28/86
/
/ ARGUMENTS:
/	bool ingameflag - set if called while playing
/
/ RETURN VALUE: none
/
/ MODULES CALLED: descrstatus(), descrlocation(), more(), fread(), fseek(), 
/	floor(), wmove(), printw(), waddstr(), distance(), wrefresh(), 
/	descrtype(), wclrtobot()
/
/ GLOBAL INPUTS: LINES, Other, Circle, Wizard, Player, *stdscr, *Playersfp
/
/ GLOBAL OUTPUTS: none
/
/ DESCRIPTION:
/	We can only see the coordinate of those closer to the origin
/	from us.
/	Kings and council of the wise can see and can be seen by everyone.
/	Palantirs are good for seeing everyone; and the valar can use
/	one to see through a 'cloak' spell.
/	The valar has no coordinates, and is completely invisible if
/	cloaked.
/
*************************************************************************/

void
userlist(ingameflag)
	bool    ingameflag;
{
	int     numusers = 0;	/* number of users on file */

	if (ingameflag && Player.p_blindness) {
		mvaddstr(8, 0, "You cannot see anyone.\n");
		return;
	}
	fseek(Playersfp, 0L, SEEK_SET);
	mvaddstr(8, 0,
	    "Name                         X         Y    Lvl Type Login    Status\n");

	while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) {
		if (Other.p_status == S_NOTUSED
		/* record is unused */
		    || (Other.p_specialtype == SC_VALAR && Other.p_status == S_CLOAKED))
			/* cloaked valar */
		{
			if (!Wizard)
				/* wizard can see everything on file */
				continue;
		}
		++numusers;

		if (ingameflag &&
		/* must be playing for the rest of these conditions */
		    (Player.p_specialtype >= SC_KING
		/* kings and higher can see others */
			|| Other.p_specialtype >= SC_KING
		/* kings and higher can be seen by others */
			|| Circle >= CIRCLE(Other.p_x, Other.p_y)
		/* those nearer the origin can be seen */
			|| Player.p_palantir)
		/* palantir enables one to see others */
		    && (Other.p_status != S_CLOAKED
			|| (Player.p_specialtype == SC_VALAR && Player.p_palantir))
		/* not cloaked; valar can see through cloak with a palantir */
		    && Other.p_specialtype != SC_VALAR)
			/* not a valar */
			/* coordinates should be printed */
			printw("%-20s  %8.0f  %8.0f ",
			    Other.p_name, Other.p_x, Other.p_y);
		else
			/* cannot see player's coordinates */
			printw("%-20s %19.19s ",
			    Other.p_name, descrlocation(&Other, TRUE));

		printw("%6.0f %s  %-9.9s%s\n", Other.p_level, descrtype(&Other, TRUE),
		    Other.p_login, descrstatus(&Other));

		if ((numusers % (LINES - 10)) == 0) {
			more(LINES - 1);
			move(9, 0);
			clrtobot();
		}
	}

	printw("Total players on file = %d\n", numusers);
	refresh();
}
/**/
/************************************************************************
/
/ FUNCTION NAME: throneroom()
/
/ FUNCTION: king stuff upon entering throne
/
/ AUTHOR: E. A. Estes, 12/16/85
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: writerecord(), fread(), fseek(), fopen(), wmove(), fclose(), 
/	fwrite(), altercoordinates(), waddstr(), fprintf()
/
/ GLOBAL INPUTS: *Energyvoidfp, Other, Player, *stdscr,
/	Enrgyvoid, *Playersfp
/
/ GLOBAL OUTPUTS: Other, Player, Changed
/
/ DESCRIPTION:
/	If player is not already king, make him/her so if the old king
/	is not playing.
/	Clear energy voids with new king.
/	Print 'decree' prompt.
/
*************************************************************************/

void
throneroom()
{
	FILE   *fp;		/* to clear energy voids */
	long    loc = 0L;	/* location of old king in player file */

	if (Player.p_specialtype < SC_KING)
		/* not already king -- assumes crown */
	{
		fseek(Playersfp, 0L, SEEK_SET);
		while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
			if (Other.p_specialtype == SC_KING && Other.p_status != S_NOTUSED)
				/* found old king */
			{
				if (Other.p_status != S_OFF)
					/* old king is playing */
				{
					mvaddstr(4, 0, "The king is playing, so you cannot steal his throne\n");
					altercoordinates(0.0, 0.0, A_NEAR);
					move(6, 0);
					return;
				} else
					/* old king is not playing - remove
					 * him/her */
				{
					Other.p_specialtype = SC_NONE;
					if (Other.p_crowns)
						--Other.p_crowns;
					writerecord(&Other, loc);
					break;
				}
			} else
				loc += SZ_PLAYERSTRUCT;

		/* make player new king */
		Changed = TRUE;
		Player.p_specialtype = SC_KING;
		mvaddstr(4, 0, "You have become king!\n");

		/* let everyone else know */
		fp = fopen(_PATH_MESS, "w");
		fprintf(fp, "All hail the new king!");
		fclose(fp);

		/* clear all energy voids; retain location of holy grail */
		fseek(Energyvoidfp, 0L, SEEK_SET);
		fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp);
		fp = fopen(_PATH_VOID, "w");
		fwrite((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, fp);
		fclose(fp);
	}
	mvaddstr(6, 0, "0:Decree  ");
}
/**/
/************************************************************************
/
/ FUNCTION NAME: dotampered()
/
/ FUNCTION: king and valar special options
/
/ AUTHOR: E. A. Estes, 2/28/86
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: writerecord(), truncstring(), fread(), fseek(), fopen(), 
/	floor(), wmove(), drandom(), fclose(), fwrite(), sscanf(), strcmp(), 
/	infloat(), waddstr(), findname(), distance(), userlist(), mvprintw(), 
/	allocvoid(), getanswer(), getstring(), wclrtoeol(), writevoid()
/
/ GLOBAL INPUTS: *Energyvoidfp, Other, Illcmd[], Wizard, Player, *stdscr, 
/	Databuf[], Enrgyvoid
/
/ GLOBAL OUTPUTS: Other, Player, Enrgyvoid
/
/ DESCRIPTION:
/	Tamper with other players.  Handle king/valar specific options.
/
*************************************************************************/

void
dotampered()
{
	short   tamper;		/* value for tampering with other players */
	char   *option;		/* pointer to option description */
	double  temp1 = 0.0, temp2 = 0.0;	/* other tampering values */
	int     ch;		/* input */
	long    loc;		/* location in energy void file */
	FILE   *fp;		/* for opening gold file */

	move(6, 0);
	clrtoeol();
	if (Player.p_specialtype < SC_COUNCIL && !Wizard)
		/* king options */
	{
		addstr("1:Transport  2:Curse  3:Energy Void  4:Bestow  5:Collect Taxes  ");

		ch = getanswer(" ", TRUE);
		move(6, 0);
		clrtoeol();
		move(4, 0);
		switch (ch) {
		case '1':	/* transport someone */
			tamper = T_TRANSPORT;
			option = "transport";
			break;

		case '2':	/* curse another */
			tamper = T_CURSED;
			option = "curse";
			break;

		case '3':	/* create energy void */
			if ((loc = allocvoid()) > 20L * SZ_VOIDSTRUCT)
				/* can only have 20 void active at once */
				mvaddstr(5, 0, "Sorry, void creation limit reached.\n");
			else {
				addstr("Enter the X Y coordinates of void ? ");
				getstring(Databuf, SZ_DATABUF);
				sscanf(Databuf, "%lf %lf", &temp1, &temp2);
				Enrgyvoid.ev_x = floor(temp1);
				Enrgyvoid.ev_y = floor(temp2);
				Enrgyvoid.ev_active = TRUE;
				writevoid(&Enrgyvoid, loc);
				mvaddstr(5, 0, "It is done.\n");
			}
			return;

		case '4':	/* bestow gold to subject */
			tamper = T_BESTOW;
			addstr("How much gold to bestow ? ");
			temp1 = infloat();
			if (temp1 > Player.p_gold || temp1 < 0) {
				mvaddstr(5, 0, "You don't have that !\n");
				return;
			}
			/* adjust gold after we are sure it will be given to
			 * someone */
			option = "give gold to";
			break;

		case '5':	/* collect accumulated taxes */
			if ((fp = fopen(_PATH_GOLD, "r+")) != NULL)
				/* collect taxes */
			{
				fread((char *) &temp1, sizeof(double), 1, fp);
				fseek(fp, 0L, SEEK_SET);
				/* clear out value */
				temp2 = 0.0;
				fwrite((char *) &temp2, sizeof(double), 1, fp);
				fclose(fp);
			}
			mvprintw(4, 0, "You have collected %.0f in gold.\n", temp1);
			Player.p_gold += floor(temp1);
			return;

		default:
			return;
		}
		/* end of king options */
	} else
		/* council of wise, valar, wizard options */
	{
		addstr("1:Heal  ");
		if (Player.p_palantir || Wizard)
			addstr("2:Seek Grail  ");
		if (Player.p_specialtype == SC_VALAR || Wizard)
			addstr("3:Throw Monster  4:Relocate  5:Bless  ");
		if (Wizard)
			addstr("6:Vaporize  ");

		ch = getanswer(" ", TRUE);
		if (!Wizard) {
			if (ch > '2' && Player.p_specialtype != SC_VALAR) {
				ILLCMD();
				return;
			}
			if (Player.p_mana < MM_INTERVENE) {
				mvaddstr(5, 0, "No mana left.\n");
				return;
			} else
				Player.p_mana -= MM_INTERVENE;
		}
		switch (ch) {
		case '1':	/* heal another */
			tamper = T_HEAL;
			option = "heal";
			break;

		case '2':	/* seek grail */
			if (Player.p_palantir)
				/* need a palantir to seek */
			{
				fseek(Energyvoidfp, 0L, SEEK_SET);
				fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp);
				temp1 = distance(Player.p_x, Enrgyvoid.ev_x, Player.p_y, Enrgyvoid.ev_y);
				temp1 += ROLL(-temp1 / 10.0, temp1 / 5.0);	/* add some error */
				mvprintw(5, 0, "The palantir says the Grail is about %.0f away.\n", temp1);
			} else
				/* no palantir */
				mvaddstr(5, 0, "You need a palantir to seek the Grail.\n");
			return;

		case '3':	/* lob monster at someone */
			mvaddstr(4, 0, "Which monster [0-99] ? ");
			temp1 = infloat();
			temp1 = MAX(0.0, MIN(99.0, temp1));
			tamper = T_MONSTER;
			option = "throw a monster at";
			break;

		case '4':	/* move another player */
			mvaddstr(4, 0, "New X Y coordinates ? ");
			getstring(Databuf, SZ_DATABUF);
			sscanf(Databuf, "%lf %lf", &temp1, &temp2);
			tamper = T_RELOCATE;
			option = "relocate";
			break;

		case '5':	/* bless a player */
			tamper = T_BLESSED;
			option = "bless";
			break;

		case '6':	/* kill off a player */
			if (Wizard) {
				tamper = T_VAPORIZED;
				option = "vaporize";
				break;
			} else
				return;

		default:
			return;
		}

		/* adjust age after we are sure intervention will be done */
		/* end of valar, etc. options */
	}

	for (;;)
		/* prompt for player to affect */
	{
		mvprintw(4, 0, "Who do you want to %s ? ", option);
		getstring(Databuf, SZ_DATABUF);
		truncstring(Databuf);

		if (Databuf[0] == '\0')
			userlist(TRUE);
		else
			break;
	}

	if (strcmp(Player.p_name, Databuf) != 0)
		/* name other than self */
	{
		if ((loc = findname(Databuf, &Other)) >= 0L) {
			if (Other.p_tampered != T_OFF) {
				mvaddstr(5, 0, "That person has something pending already.\n");
				return;
			} else {
				if (tamper == T_RELOCATE
				    && CIRCLE(temp1, temp2) < CIRCLE(Other.p_x, Other.p_y)
				    && !Wizard)
					mvaddstr(5, 0, "Cannot move someone closer to the Lord's Chamber.\n");
				else {
					if (tamper == T_BESTOW)
						Player.p_gold -= floor(temp1);
					if (!Wizard && (tamper == T_HEAL || tamper == T_MONSTER ||
						tamper == T_RELOCATE || tamper == T_BLESSED))
						Player.p_age += N_AGE;	/* age penalty */
					Other.p_tampered = tamper;
					Other.p_1scratch = floor(temp1);
					Other.p_2scratch = floor(temp2);
					writerecord(&Other, loc);
					mvaddstr(5, 0, "It is done.\n");
				}
				return;
			}
		} else
			/* player not found */
			mvaddstr(5, 0, "There is no one by that name.\n");
	} else
		/* self */
		mvaddstr(5, 0, "You may not do it to yourself!\n");
}
/**/
/************************************************************************
/
/ FUNCTION NAME: writevoid()
/
/ FUNCTION: update energy void entry in energy void file
/
/ AUTHOR: E. A. Estes, 12/4/85
/
/ ARGUMENTS:
/	struct energyvoid *vp - pointer to structure to write to file
/	long loc - location in file to update
/
/ RETURN VALUE: none
/
/ MODULES CALLED: fseek(), fwrite(), fflush()
/
/ GLOBAL INPUTS: *Energyvoidfp
/
/ GLOBAL OUTPUTS: none
/
/ DESCRIPTION:
/	Write out energy void structure at specified location.
/
*************************************************************************/

void
writevoid(vp, loc)
	struct energyvoid *vp;
	long    loc;
{

	fseek(Energyvoidfp, loc, SEEK_SET);
	fwrite((char *) vp, SZ_VOIDSTRUCT, 1, Energyvoidfp);
	fflush(Energyvoidfp);
	fseek(Energyvoidfp, 0L, SEEK_SET);
}
/**/
/************************************************************************
/
/ FUNCTION NAME: allocvoid()
/
/ FUNCTION: allocate space for a new energy void
/
/ AUTHOR: E. A. Estes, 12/4/85
/
/ ARGUMENTS: none
/
/ RETURN VALUE: location of new energy void space
/
/ MODULES CALLED: fread(), fseek()
/
/ GLOBAL INPUTS: *Energyvoidfp, Enrgyvoid
/
/ GLOBAL OUTPUTS: none
/
/ DESCRIPTION:
/	Search energy void file for an inactive entry and return its
/	location.
/	If no inactive ones are found, return one more than last location.
/
*************************************************************************/

long
allocvoid()
{
	long    loc = 0L;	/* location of new energy void */

	fseek(Energyvoidfp, 0L, SEEK_SET);
	while (fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1)
		if (Enrgyvoid.ev_active)
			loc += SZ_VOIDSTRUCT;
		else
			break;

	return (loc);
}