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