Home | History | Annotate | Line # | Download | only in phantasia
fight.c revision 1.2
      1 /*	$NetBSD: fight.c,v 1.2 1995/03/24 03:58:39 cgd Exp $	*/
      2 
      3 /*
      4  * fight.c   Phantasia monster fighting routines
      5  */
      6 
      7 #include "include.h"
      8 
      9 /************************************************************************
     10 /
     11 / FUNCTION NAME: encounter()
     12 /
     13 / FUNCTION: monster battle routine
     14 /
     15 / AUTHOR: E. A. Estes, 2/20/86
     16 /
     17 / ARGUMENTS:
     18 /	int particular - particular monster to fight if >= 0
     19 /
     20 / RETURN VALUE: none
     21 /
     22 / MODULES CALLED: monsthits(), playerhits(), readmessage(), callmonster(),
     23 /	writerecord(), pickmonster(), displaystats(), pow(), cancelmonster(),
     24 /	awardtreasure(), more(), death(), wmove(), setjmp(), drandom(), printw(),
     25 /	longjmp(), wrefresh(), mvprintw(), wclrtobot()
     26 /
     27 / GLOBAL INPUTS: Curmonster, Whichmonster, LINES, Lines, Circle, Shield,
     28 /	Player, *stdscr, Fileloc, Fightenv[], *Enemyname
     29 /
     30 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player, Luckout
     31 /
     32 / DESCRIPTION:
     33 /	Choose a monster and check against some special types.
     34 /	Arbitrate between monster and player.  Watch for either
     35 /	dying.
     36 /
     37 /************************************************************************/
     38 
     39 encounter(particular)
     40 int	particular;
     41 {
     42 bool	firsthit = Player.p_blessing;	/* set if player gets the first hit */
     43 int	flockcnt = 1;			/* how many time flocked */
     44 
     45     /* let others know what we are doing */
     46     Player.p_status = S_MONSTER;
     47     writerecord(&Player, Fileloc);
     48 
     49 #ifdef SYS5
     50     flushinp();
     51 #endif
     52 
     53     Shield = 0.0;		/* no shield up yet */
     54 
     55     if (particular >= 0)
     56 	/* monster is specified */
     57 	Whichmonster = particular;
     58     else
     59 	/* pick random monster */
     60 	Whichmonster = pickmonster();
     61 
     62     setjmp(Fightenv);		/* this is to enable changing fight state */
     63 
     64     move(6, 0);
     65     clrtobot();			/* clear bottom area of screen */
     66 
     67     Lines = 9;
     68     callmonster(Whichmonster);	/* set up monster to fight */
     69 
     70     Luckout = FALSE;		/* haven't tried to luckout yet */
     71 
     72     if (Curmonster.m_type == SM_MORGOTH)
     73 	mvprintw(4, 0, "You've encountered %s, Bane of the Council and Valar.\n",
     74 	    Enemyname);
     75 
     76     if (Curmonster.m_type == SM_UNICORN)
     77 	{
     78 	if (Player.p_virgin)
     79 	    {
     80 	    printw("You just subdued %s, thanks to the virgin.\n", Enemyname);
     81 	    Player.p_virgin = FALSE;
     82 	    }
     83 	else
     84 	    {
     85 	    printw("You just saw %s running away!\n", Enemyname);
     86 	    Curmonster.m_experience = 0.0;
     87 	    Curmonster.m_treasuretype = 0;
     88 	    }
     89 	}
     90     else
     91 	/* not a special monster */
     92 	for (;;)
     93 	    /* print header, and arbitrate between player and monster */
     94 	    {
     95 	    mvprintw(6, 0, "You are being attacked by %s,   EXP: %.0f   (Size: %.0f)\n",
     96 		Enemyname, Curmonster.m_experience, Circle);
     97 
     98 	    displaystats();
     99 	    mvprintw(1, 26, "%20.0f", Player.p_energy + Shield);	/* overprint energy */
    100 	    readmessage();
    101 
    102 	    if (Curmonster.m_type == SM_DARKLORD
    103 		&& Player.p_blessing
    104 		&& Player.p_charms > 0)
    105 		/* overpower Dark Lord with blessing and charm */
    106 		{
    107 		mvprintw(7, 0, "You just overpowered %s!", Enemyname);
    108 		Lines = 8;
    109 		Player.p_blessing = FALSE;
    110 		--Player.p_charms;
    111 		break;
    112 		}
    113 
    114 	    /* allow paralyzed monster to wake up */
    115 	    Curmonster.m_speed = MIN(Curmonster.m_speed + 1.0, Curmonster.m_maxspeed);
    116 
    117 	    if (drandom() * Curmonster.m_speed > drandom() * Player.p_speed
    118 		/* monster is faster */
    119 		&& Curmonster.m_type != SM_DARKLORD
    120 		/* not D. L. */
    121 		&& Curmonster.m_type != SM_SHRIEKER
    122 		/* not mimic */
    123 		&& !firsthit)
    124 		/* monster gets a hit */
    125 		monsthits();
    126 	    else
    127 		/* player gets a hit */
    128 		{
    129 		firsthit = FALSE;
    130 		playerhits();
    131 		}
    132 
    133 	    refresh();
    134 
    135 	    if (Lines > LINES - 2)
    136 		/* near bottom of screen - pause */
    137 		{
    138 		more(Lines);
    139 		move(Lines = 8, 0);
    140 		clrtobot();
    141 		}
    142 
    143 	    if (Player.p_energy <= 0.0)
    144 		/* player died */
    145 		{
    146 		more(Lines);
    147 		death(Enemyname);
    148 		cancelmonster();
    149 		break;		/* fight ends if the player is saved from death */
    150 		}
    151 
    152 	    if (Curmonster.m_energy <= 0.0)
    153 		/* monster died */
    154 		break;
    155 	    }
    156 
    157     /* give player credit for killing monster */
    158     Player.p_experience += Curmonster.m_experience;
    159 
    160     if (drandom() < Curmonster.m_flock / 100.0)
    161 	/* monster flocks */
    162 	{
    163 	more(Lines);
    164 	++flockcnt;
    165 	longjmp(Fightenv, 0);
    166 	/*NOTREACHED*/
    167 	}
    168     else if (Circle > 1.0
    169 	&& Curmonster.m_treasuretype > 0
    170 	&& drandom() > 0.2 + pow(0.4, (double) (flockcnt / 3 + Circle / 3.0)))
    171 	/* monster has treasure; this takes # of flocks and size into account */
    172 	{
    173 	more(Lines);
    174 	awardtreasure();
    175 	}
    176 
    177     /* pause before returning */
    178     getyx(stdscr, Lines, flockcnt);
    179     more(Lines + 1);
    180 
    181     Player.p_ring.ring_inuse = FALSE;	/* not using ring */
    182 
    183     /* clean up the screen */
    184     move(4, 0);
    185     clrtobot();
    186 }
    187 /**/
    189 /************************************************************************
    190 /
    191 / FUNCTION NAME: pickmonster()
    192 /
    193 / FUNCTION: choose a monster based upon where we are
    194 /
    195 / AUTHOR: E. A. Estes, 2/20/86
    196 /
    197 / ARGUMENTS: none
    198 /
    199 / RETURN VALUE: monster number to call
    200 /
    201 / MODULES CALLED: floor(), drandom()
    202 /
    203 / GLOBAL INPUTS: Marsh, Circle, Player
    204 /
    205 / GLOBAL OUTPUTS: none
    206 /
    207 / DESCRIPTION:
    208 /	Certain monsters can be found in certain areas of the grid.
    209 /	We take care of rolling them here.
    210 /	Unfortunately, this routine assumes that the monster data
    211 /	base is arranged in a particular order.  If the data base
    212 /	is altered (to add monsters, or make them tougher), this
    213 /	routine may also need to be changed.
    214 /
    215 /************************************************************************/
    216 
    217 pickmonster()
    218 {
    219     if (Player.p_specialtype == SC_VALAR)
    220 	/* even chance of any monster */
    221 	return((int) ROLL(0.0, 100.0));
    222 
    223     if (Marsh)
    224 	/* water monsters */
    225 	return((int) ROLL(0.0, 15.0));
    226 
    227     else if (Circle > 24)
    228 	/* even chance of all non-water monsters */
    229 	return((int) ROLL(14.0, 86.0));
    230 
    231     else if (Circle > 15)
    232 	/* chance of all non-water monsters, weighted toward middle */
    233 	return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 37.0)));
    234 
    235     else if (Circle > 8)
    236 	/* not all non-water monsters, weighted toward middle */
    237 	return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 26.0)));
    238 
    239     else if (Circle > 3)
    240 	/* even chance of some tamer non-water monsters */
    241 	return((int) ROLL(14.0, 50.0));
    242 
    243     else
    244 	/* even chance of some of the tamest non-water monsters */
    245 	return((int) ROLL(14.0, 25.0));
    246 }
    247 /**/
    249 /************************************************************************
    250 /
    251 / FUNCTION NAME: playerhits()
    252 /
    253 / FUNCTION: prompt player for action in monster battle, and process
    254 /
    255 / AUTHOR: E. A. Estes, 12/4/85
    256 /
    257 / ARGUMENTS: none
    258 /
    259 / RETURN VALUE: none
    260 /
    261 / MODULES CALLED: hitmonster(), throwspell(), inputoption(), cancelmonster(),
    262 /	floor(), wmove(), drandom(), altercoordinates(), waddstr(), mvprintw(),
    263 /	wclrtoeol(), wclrtobot()
    264 /
    265 / GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, Luckout, *Enemyname
    266 /
    267 / GLOBAL OUTPUTS: Curmonster, Lines, Player, Luckout
    268 /
    269 / DESCRIPTION:
    270 /	Process all monster battle options.
    271 /
    272 /************************************************************************/
    273 
    274 playerhits()
    275 {
    276 double	inflict;	/* damage inflicted */
    277 int	ch;		/* input */
    278 
    279     mvaddstr(7, 0, "1:Melee  2:Skirmish  3:Evade  4:Spell  5:Nick  ");
    280 
    281     if (!Luckout)
    282 	/* haven't tried to luckout yet */
    283 	if (Curmonster.m_type == SM_MORGOTH)
    284 	    /* cannot luckout against Morgoth */
    285 	    addstr("6:Ally  ");
    286 	else
    287 	    addstr("6:Luckout  ");
    288 
    289     if (Player.p_ring.ring_type != R_NONE)
    290 	/* player has a ring */
    291 	addstr("7:Use Ring  ");
    292     else
    293 	clrtoeol();
    294 
    295     ch = inputoption();
    296 
    297     move(8, 0);
    298     clrtobot();			/* clear any messages from before */
    299     Lines = 9;
    300     mvaddstr(4, 0, "\n\n");	/* clear status area */
    301 
    302     switch (ch)
    303 	{
    304 	case 'T':		/* timeout; lose turn */
    305 	    break;
    306 
    307 	case ' ':
    308 	case '1':		/* melee */
    309 	    /* melee affects monster's energy and strength */
    310 	    inflict = ROLL(Player.p_might / 2.0 + 5.0, 1.3 * Player.p_might)
    311 		+ (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
    312 
    313 	    Curmonster.m_melee += inflict;
    314 	    Curmonster.m_strength = Curmonster.m_o_strength
    315 		- Curmonster.m_melee / Curmonster.m_o_energy
    316 		* Curmonster.m_o_strength / 4.0;
    317 	    hitmonster(inflict);
    318 	    break;
    319 
    320 	case '2':		/* skirmish */
    321 	    /* skirmish affects monter's energy and speed */
    322 	    inflict = ROLL(Player.p_might / 3.0 + 3.0, 1.1 * Player.p_might)
    323 		+ (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
    324 
    325 	    Curmonster.m_skirmish += inflict;
    326 	    Curmonster.m_maxspeed = Curmonster.m_o_speed
    327 		- Curmonster.m_skirmish / Curmonster.m_o_energy
    328 		* Curmonster.m_o_speed / 4.0;
    329 	    hitmonster(inflict);
    330 	    break;
    331 
    332 	case '3':		/* evade */
    333 	    /* use brains and speed to try to evade */
    334 	    if ((Curmonster.m_type == SM_DARKLORD
    335 		|| Curmonster.m_type == SM_SHRIEKER
    336 		/* can always run from D. L. and shrieker */
    337 		|| drandom() * Player.p_speed * Player.p_brains
    338 		    > drandom() * Curmonster.m_speed * Curmonster.m_brains)
    339 		&& (Curmonster.m_type != SM_MIMIC))
    340 		/* cannot run from mimic */
    341 		{
    342 		mvaddstr(Lines++, 0, "You got away!");
    343 		cancelmonster();
    344 		altercoordinates(0.0, 0.0, A_NEAR);
    345 		}
    346 	    else
    347 		mvprintw(Lines++, 0, "%s is still after you!", Enemyname);
    348 
    349 	    break;
    350 
    351 	case 'M':
    352 	case '4':		/* magic spell */
    353 	    throwspell();
    354 	    break;
    355 
    356 	case '5':		/* nick */
    357 	    /* hit 1 plus sword; give some experience */
    358 	    inflict = 1.0 + Player.p_sword;
    359 	    Player.p_experience += floor(Curmonster.m_experience / 10.0);
    360 	    Curmonster.m_experience *= 0.92;
    361 	    /* monster gets meaner */
    362 	    Curmonster.m_maxspeed += 2.0;
    363 	    Curmonster.m_speed = (Curmonster.m_speed < 0.0) ? 0.0 : Curmonster.m_speed + 2.0;
    364 	    if (Curmonster.m_type == SM_DARKLORD)
    365 		/* Dark Lord; doesn't like to be nicked */
    366 		{
    367 		mvprintw(Lines++, 0,
    368 		    "You hit %s %.0f times, and made him mad!", Enemyname, inflict);
    369 		Player.p_quickness /= 2.0;
    370 		altercoordinates(0.0, 0.0, A_FAR);
    371 		cancelmonster();
    372 		}
    373 	    else
    374 		hitmonster(inflict);
    375 	    break;
    376 
    377 	case 'B':
    378 	case '6':	/* luckout */
    379 	    if (Luckout)
    380 		mvaddstr(Lines++, 0, "You already tried that.");
    381 	    else
    382 		{
    383 		Luckout = TRUE;
    384 		if (Curmonster.m_type == SM_MORGOTH)
    385 		    /* Morgoth; ally */
    386 		    {
    387 		    if (drandom() < Player.p_sin / 100.0)
    388 			{
    389 			mvprintw(Lines++, 0, "%s accepted!", Enemyname);
    390 			cancelmonster();
    391 			}
    392 		    else
    393 			mvaddstr(Lines++, 0, "Nope, he's not interested.");
    394 		    }
    395 		else
    396 		    /* normal monster; use brains for success */
    397 		    {
    398 		    if ((drandom() + 0.333) * Player.p_brains
    399 			< (drandom() + 0.333) * Curmonster.m_brains)
    400 			mvprintw(Lines++, 0, "You blew it, %s.", Player.p_name);
    401 		    else
    402 			{
    403 			mvaddstr(Lines++, 0, "You made it!");
    404 			Curmonster.m_energy = 0.0;
    405 			}
    406 		    }
    407 		}
    408 	    break;
    409 
    410 	case '7':		/* use ring */
    411 	    if (Player.p_ring.ring_type != R_NONE)
    412 		{
    413 		mvaddstr(Lines++, 0, "Now using ring.");
    414 		Player.p_ring.ring_inuse = TRUE;
    415 		if (Player.p_ring.ring_type != R_DLREG)
    416 		    /* age ring */
    417 		    --Player.p_ring.ring_duration;
    418 		}
    419 	    break;
    420 	}
    421 
    422 }
    423 /**/
    425 /************************************************************************
    426 /
    427 / FUNCTION NAME: monsthits()
    428 /
    429 / FUNCTION: process a monster hitting the player
    430 /
    431 / AUTHOR: E. A. Estes, 12/4/85
    432 /
    433 / ARGUMENTS: none
    434 /
    435 / RETURN VALUE: none
    436 /
    437 / MODULES CALLED: cancelmonster(), scramblestats(), more(), floor(), wmove(),
    438 /	drandom(), altercoordinates(), longjmp(), waddstr(), mvprintw(),
    439 /	getanswer()
    440 /
    441 / GLOBAL INPUTS: Curmonster, Lines, Circle, Shield, Player, *stdscr,
    442 /	Fightenv[], *Enemyname
    443 /
    444 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player,
    445 /	*Enemyname
    446 /
    447 / DESCRIPTION:
    448 /	Handle all special monsters here.  If the monster is not a special
    449 /	one, simply roll a hit against the player.
    450 /
    451 /************************************************************************/
    452 
    453 monsthits()
    454 {
    455 double	inflict;		/* damage inflicted */
    456 int	ch;			/* input */
    457 
    458     switch (Curmonster.m_type)
    459 	/* may be a special monster */
    460 	{
    461 	case SM_DARKLORD:
    462 	    /* hits just enough to kill player */
    463 	    inflict = (Player.p_energy + Shield) * 1.02;
    464 	    goto SPECIALHIT;
    465 
    466 	case SM_SHRIEKER:
    467 	    /* call a big monster */
    468 	    mvaddstr(Lines++, 0,
    469 		"Shrieeeek!!  You scared it, and it called one of its friends.");
    470 	    more(Lines);
    471 	    Whichmonster = (int) ROLL(70.0, 30.0);
    472 	    longjmp(Fightenv, 0);
    473 	    /*NOTREACHED*/
    474 
    475 	case SM_BALROG:
    476 	    /* take experience away */
    477 	    inflict = ROLL(10.0, Curmonster.m_strength);
    478 	    inflict = MIN(Player.p_experience, inflict);
    479 	    mvprintw(Lines++, 0,
    480 		"%s took away %.0f experience points.", Enemyname, inflict);
    481 	    Player.p_experience -= inflict;
    482 	    return;
    483 
    484 	case SM_FAERIES:
    485 	    if (Player.p_holywater > 0)
    486 		/* holy water kills when monster tries to hit */
    487 		{
    488 		mvprintw(Lines++, 0, "Your holy water killed it!");
    489 		--Player.p_holywater;
    490 		Curmonster.m_energy = 0.0;
    491 		return;
    492 		}
    493 	    break;
    494 
    495 	case SM_NONE:
    496 	    /* normal hit */
    497 	    break;
    498 
    499 	default:
    500 	    if (drandom() > 0.2)
    501 		/* normal hit */
    502 		break;
    503 
    504 	    /* else special things */
    505 	    switch (Curmonster.m_type)
    506 		{
    507 		case SM_LEANAN:
    508 		    /* takes some of the player's strength */
    509 		    inflict = ROLL(1.0, (Circle - 1.0) / 2.0);
    510 		    inflict = MIN(Player.p_strength, inflict);
    511 		    mvprintw(Lines++, 0, "%s sapped %0.f of your strength!",
    512 			Enemyname, inflict);
    513 		    Player.p_strength -= inflict;
    514 		    Player.p_might -= inflict;
    515 		    break;
    516 
    517 		case SM_SARUMAN:
    518 		    if (Player.p_palantir)
    519 			/* take away palantir */
    520 			{
    521 			mvprintw(Lines++, 0, "Wormtongue stole your palantir!");
    522 			Player.p_palantir = FALSE;
    523 			}
    524 		    else if (drandom() > 0.5)
    525 			/* gems turn to gold */
    526 			{
    527 			mvprintw(Lines++, 0,
    528 			    "%s transformed your gems into gold!", Enemyname);
    529 			Player.p_gold += Player.p_gems;
    530 			Player.p_gems = 0.0;
    531 			}
    532 		    else
    533 			/* scramble some stats */
    534 			{
    535 			mvprintw(Lines++, 0, "%s scrambled your stats!", Enemyname);
    536 			scramblestats();
    537 			}
    538 		    break;
    539 
    540 		case SM_THAUMATURG:
    541 		    /* transport player */
    542 		    mvprintw(Lines++, 0, "%s transported you!", Enemyname);
    543 		    altercoordinates(0.0, 0.0, A_FAR);
    544 		    cancelmonster();
    545 		    break;
    546 
    547 		case SM_VORTEX:
    548 		    /* suck up some mana */
    549 		    inflict = ROLL(0, 7.5 * Circle);
    550 		    inflict = MIN(Player.p_mana, floor(inflict));
    551 		    mvprintw(Lines++, 0,
    552 			"%s sucked up %.0f of your mana!", Enemyname, inflict);
    553 		    Player.p_mana -= inflict;
    554 		    break;
    555 
    556 		case SM_NAZGUL:
    557 		    /* try to take ring if player has one */
    558 		    if (Player.p_ring.ring_type != R_NONE)
    559 			/* player has a ring */
    560 			{
    561 			mvaddstr(Lines++, 0, "Will you relinguish your ring ? ");
    562 			ch = getanswer("YN", FALSE);
    563 			if (ch == 'Y')
    564 			    /* take ring away */
    565 			    {
    566 			    Player.p_ring.ring_type = R_NONE;
    567 			    Player.p_ring.ring_inuse = FALSE;
    568 			    cancelmonster();
    569 			    break;
    570 			    }
    571 			}
    572 
    573 		    /* otherwise, take some brains */
    574 		    mvprintw(Lines++, 0,
    575 			"%s neutralized 1/5 of your brain!", Enemyname);
    576 		    Player.p_brains *= 0.8;
    577 		    break;
    578 
    579 		case SM_TIAMAT:
    580 		    /* take some gold and gems */
    581 		    mvprintw(Lines++, 0,
    582 			"%s took half your gold and gems and flew off.", Enemyname);
    583 		    Player.p_gold /= 2.0;
    584 		    Player.p_gems /= 2.0;
    585 		    cancelmonster();
    586 		    break;
    587 
    588 		case SM_KOBOLD:
    589 		    /* steal a gold piece and run */
    590 		    mvprintw(Lines++, 0,
    591 			"%s stole one gold piece and ran away.", Enemyname);
    592 		    Player.p_gold = MAX(0.0, Player.p_gold - 1.0);
    593 		    cancelmonster();
    594 		    break;
    595 
    596 		case SM_SHELOB:
    597 		    /* bite and (medium) poison */
    598 		    mvprintw(Lines++, 0,
    599 			"%s has bitten and poisoned you!", Enemyname);
    600 		    Player.p_poison -= 1.0;
    601 		    break;
    602 
    603 		case SM_LAMPREY:
    604 		    /*  bite and (small) poison */
    605 		    mvprintw(Lines++, 0, "%s bit and poisoned you!", Enemyname);
    606 		    Player.p_poison += 0.25;
    607 		    break;
    608 
    609 		case SM_BONNACON:
    610 		    /* fart and run */
    611 		    mvprintw(Lines++, 0, "%s farted and scampered off.", Enemyname);
    612 		    Player.p_energy /= 2.0;		/* damage from fumes */
    613 		    cancelmonster();
    614 		    break;
    615 
    616 		case SM_SMEAGOL:
    617 		    if (Player.p_ring.ring_type != R_NONE)
    618 			/* try to steal ring */
    619 			{
    620 			mvprintw(Lines++, 0,
    621 			    "%s tried to steal your ring, ", Enemyname);
    622 			if (drandom() > 0.1)
    623 			    addstr("but was unsuccessful.");
    624 			else
    625 			    {
    626 			    addstr("and ran away with it!");
    627 			    Player.p_ring.ring_type = R_NONE;
    628 			    cancelmonster();
    629 			    }
    630 			}
    631 		    break;
    632 
    633 		case SM_SUCCUBUS:
    634 		    /* inflict damage through shield */
    635 		    inflict = ROLL(15.0, Circle * 10.0);
    636 		    inflict = MIN(inflict, Player.p_energy);
    637 		    mvprintw(Lines++, 0, "%s sapped %.0f of your energy.",
    638 			Enemyname, inflict);
    639 		    Player.p_energy -= inflict;
    640 		    break;
    641 
    642 		case SM_CERBERUS:
    643 		    /* take all metal treasures */
    644 		    mvprintw(Lines++, 0,
    645 			"%s took all your metal treasures!", Enemyname);
    646 		    Player.p_crowns = 0;
    647 		    Player.p_sword =
    648 		    Player.p_shield =
    649 		    Player.p_gold = 0.0;
    650 		    cancelmonster();
    651 		    break;
    652 
    653 		case SM_UNGOLIANT:
    654 		    /* (large) poison and take a quickness */
    655 		    mvprintw(Lines++, 0,
    656 			"%s poisoned you, and took one quik.", Enemyname);
    657 		    Player.p_poison += 5.0;
    658 		    Player.p_quickness -= 1.0;
    659 		    break;
    660 
    661 		case SM_JABBERWOCK:
    662 		    /* fly away, and leave either a Jubjub bird or Bonnacon */
    663 		    mvprintw(Lines++, 0,
    664 			"%s flew away, and left you to contend with one of its friends.",
    665 			Enemyname);
    666 		    Whichmonster = 55 + (drandom() > 0.5) ? 22 : 0;
    667 		    longjmp(Fightenv, 0);
    668 		    /*NOTREACHED*/
    669 
    670 		case SM_TROLL:
    671 		    /* partially regenerate monster */
    672 		    mvprintw(Lines++, 0,
    673 			"%s partially regenerated his energy.!", Enemyname);
    674 		    Curmonster.m_energy +=
    675 			floor((Curmonster.m_o_energy - Curmonster.m_energy) / 2.0);
    676 		    Curmonster.m_strength = Curmonster.m_o_strength;
    677 		    Curmonster.m_melee = Curmonster.m_skirmish = 0.0;
    678 		    Curmonster.m_maxspeed = Curmonster.m_o_speed;
    679 		    break;
    680 
    681 		case SM_WRAITH:
    682 		    if (!Player.p_blindness)
    683 			/* make blind */
    684 			{
    685 			mvprintw(Lines++, 0, "%s blinded you!", Enemyname);
    686 			Player.p_blindness = TRUE;
    687 			Enemyname = "A monster";
    688 			}
    689 		    break;
    690 		}
    691 	    return;
    692 	}
    693 
    694     /* fall through to here if monster inflicts a normal hit */
    695     inflict = drandom() * Curmonster.m_strength + 0.5;
    696 SPECIALHIT:
    697     mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, inflict);
    698 
    699     if ((Shield -= inflict) < 0)
    700 	{
    701 	Player.p_energy += Shield;
    702 	Shield = 0.0;
    703 	}
    704 }
    705 /**/
    707 /************************************************************************
    708 /
    709 / FUNCTION NAME: cancelmonster()
    710 /
    711 / FUNCTION: mark current monster as no longer active
    712 /
    713 / AUTHOR: E. A. Estes, 12/4/85
    714 /
    715 / ARGUMENTS: none
    716 /
    717 / RETURN VALUE: none
    718 /
    719 / MODULES CALLED: none
    720 /
    721 / GLOBAL INPUTS: none
    722 /
    723 / GLOBAL OUTPUTS: Curmonster
    724 /
    725 / DESCRIPTION:
    726 /	Clear current monster's energy, experience, treasure type, and
    727 /	flock.  This is the same as having the monster run away.
    728 /
    729 /************************************************************************/
    730 
    731 cancelmonster()
    732 {
    733     Curmonster.m_energy = 0.0;
    734     Curmonster.m_experience = 0.0;
    735     Curmonster.m_treasuretype = 0;
    736     Curmonster.m_flock = 0.0;
    737 }
    738 /**/
    740 /************************************************************************
    741 /
    742 / FUNCTION NAME: hitmonster()
    743 /
    744 / FUNCTION: inflict damage upon current monster
    745 /
    746 / AUTHOR: E. A. Estes, 12/4/85
    747 /
    748 / ARGUMENTS:
    749 /	double inflict - damage to inflict upon monster
    750 /
    751 / RETURN VALUE: none
    752 /
    753 / MODULES CALLED: monsthits(), wmove(), strcmp(), waddstr(), mvprintw()
    754 /
    755 / GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, *Enemyname
    756 /
    757 / GLOBAL OUTPUTS: Curmonster, Lines
    758 /
    759 / DESCRIPTION:
    760 /	Hit monster specified number of times.  Handle when monster dies,
    761 /	and a few special monsters.
    762 /
    763 /************************************************************************/
    764 
    765 hitmonster(inflict)
    766 double	inflict;
    767 {
    768     mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, inflict);
    769     Curmonster.m_energy -= inflict;
    770     if (Curmonster.m_energy > 0.0)
    771 	{
    772 	if (Curmonster.m_type == SM_DARKLORD || Curmonster.m_type == SM_SHRIEKER)
    773 	    /* special monster didn't die */
    774 	    monsthits();
    775 	}
    776     else
    777 	/* monster died.  print message. */
    778 	{
    779 	if (Curmonster.m_type == SM_MORGOTH)
    780 	    mvaddstr(Lines++, 0, "You have defeated Morgoth, but he may return. . .");
    781 	else
    782 	    /* all other types of monsters */
    783 	    {
    784 	    mvprintw(Lines++, 0, "You killed it.  Good work, %s.", Player.p_name);
    785 
    786 	    if (Curmonster.m_type == SM_MIMIC
    787 		&& strcmp(Curmonster.m_name, "A Mimic") != 0
    788 		&& !Player.p_blindness)
    789 		mvaddstr(Lines++, 0, "The body slowly changes into the form of a mimic.");
    790 	    }
    791 	}
    792 }
    793 /**/
    795 /************************************************************************
    796 /
    797 / FUNCTION NAME: throwspell()
    798 /
    799 / FUNCTION: throw a magic spell
    800 /
    801 / AUTHOR: E. A. Estes, 12/4/85
    802 /
    803 / ARGUMENTS: none
    804 /
    805 / RETURN VALUE: none
    806 /
    807 / MODULES CALLED: hitmonster(), cancelmonster(), sqrt(), floor(), wmove(),
    808 /	drandom(), altercoordinates(), longjmp(), infloat(), waddstr(), mvprintw(),
    809 /	getanswer()
    810 /
    811 / GLOBAL INPUTS: Curmonster, Whichmonster, Nomana[], Player, *stdscr,
    812 /	Fightenv[], Illspell[], *Enemyname
    813 /
    814 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Shield, Player
    815 /
    816 / DESCRIPTION:
    817 /	Prompt player and process magic spells.
    818 /
    819 /************************************************************************/
    820 
    821 throwspell()
    822 {
    823 double	inflict;	/* damage inflicted */
    824 double	dtemp;		/* for dtemporary calculations */
    825 int	ch;		/* input */
    826 
    827     mvaddstr(7, 0, "\n\n");		/* clear menu area */
    828 
    829     if (Player.p_magiclvl >= ML_ALLORNOTHING)
    830 	mvaddstr(7, 0, "1:All or Nothing  ");
    831     if (Player.p_magiclvl >= ML_MAGICBOLT)
    832 	addstr("2:Magic Bolt  ");
    833     if (Player.p_magiclvl >= ML_FORCEFIELD)
    834 	addstr("3:Force Field  ");
    835     if (Player.p_magiclvl >= ML_XFORM)
    836 	addstr("4:Transform  ");
    837     if (Player.p_magiclvl >= ML_INCRMIGHT)
    838 	addstr("5:Increase Might\n");
    839     if (Player.p_magiclvl >= ML_INVISIBLE)
    840 	mvaddstr(8, 0, "6:Invisibility  ");
    841     if (Player.p_magiclvl >= ML_XPORT)
    842 	addstr("7:Transport  ");
    843     if (Player.p_magiclvl >= ML_PARALYZE)
    844 	addstr("8:Paralyze  ");
    845     if (Player.p_specialtype >= SC_COUNCIL)
    846 	addstr("9:Specify");
    847     mvaddstr(4, 0, "Spell ? ");
    848 
    849     ch = getanswer(" ", TRUE);
    850 
    851     mvaddstr(7, 0, "\n\n");		/* clear menu area */
    852 
    853     if (Curmonster.m_type == SM_MORGOTH && ch != '3')
    854 	/* can only throw force field against Morgoth */
    855 	ILLSPELL();
    856     else
    857 	switch (ch)
    858 	    {
    859 	    case '1':   /* all or nothing */
    860 		if (drandom() < 0.25)
    861 		    /* success */
    862 		    {
    863 		    inflict = Curmonster.m_energy * 1.01 + 1.0;
    864 
    865 		    if (Curmonster.m_type == SM_DARKLORD)
    866 			/* all or nothing doesn't quite work against D. L. */
    867 			inflict *= 0.9;
    868 		    }
    869 		else
    870 		    /* failure -- monster gets stronger and quicker */
    871 		    {
    872 		    Curmonster.m_o_strength = Curmonster.m_strength *= 2.0;
    873 		    Curmonster.m_maxspeed *= 2.0;
    874 		    Curmonster.m_o_speed *= 2.0;
    875 
    876 		    /* paralyzed monsters wake up a bit */
    877 		    Curmonster.m_speed = MAX(1.0, Curmonster.m_speed * 2.0);
    878 		    }
    879 
    880 		if (Player.p_mana >= MM_ALLORNOTHING)
    881 		    /* take a mana if player has one */
    882 		    Player.p_mana -= MM_ALLORNOTHING;
    883 
    884 		hitmonster(inflict);
    885 		break;
    886 
    887 	    case '2':   /* magic bolt */
    888 		if (Player.p_magiclvl < ML_MAGICBOLT)
    889 		    ILLSPELL();
    890 		else
    891 		    {
    892 		    do
    893 			/* prompt for amount to expend */
    894 			{
    895 			mvaddstr(4, 0, "How much mana for bolt? ");
    896 			dtemp = floor(infloat());
    897 			}
    898 		    while (dtemp < 0.0 || dtemp > Player.p_mana);
    899 
    900 		    Player.p_mana -= dtemp;
    901 
    902 		    if (Curmonster.m_type == SM_DARKLORD)
    903 			/* magic bolts don't work against D. L. */
    904 			inflict = 0.0;
    905 		    else
    906 			inflict = dtemp * ROLL(15.0, sqrt(Player.p_magiclvl / 3.0 + 1.0));
    907 		    mvaddstr(5, 0, "Magic Bolt fired!\n");
    908 		    hitmonster(inflict);
    909 		    }
    910 		break;
    911 
    912 	    case '3':   /* force field */
    913 		if (Player.p_magiclvl < ML_FORCEFIELD)
    914 		    ILLSPELL();
    915 		else if (Player.p_mana < MM_FORCEFIELD)
    916 		    NOMANA();
    917 		else
    918 		    {
    919 		    Player.p_mana -= MM_FORCEFIELD;
    920 		    Shield = (Player.p_maxenergy + Player.p_shield) * 4.2 + 45.0;
    921 		    mvaddstr(5, 0, "Force Field up.\n");
    922 		    }
    923 		break;
    924 
    925 	    case '4':   /* transform */
    926 		if (Player.p_magiclvl < ML_XFORM)
    927 		    ILLSPELL();
    928 		else if (Player.p_mana < MM_XFORM)
    929 		    NOMANA();
    930 		else
    931 		    {
    932 		    Player.p_mana -= MM_XFORM;
    933 		    Whichmonster = (int) ROLL(0.0, 100.0);
    934 		    longjmp(Fightenv, 0);
    935 		    /*NOTREACHED*/
    936 		    }
    937 		break;
    938 
    939 	    case '5':   /* increase might */
    940 		if (Player.p_magiclvl < ML_INCRMIGHT)
    941 		    ILLSPELL();
    942 		else if (Player.p_mana < MM_INCRMIGHT)
    943 		    NOMANA();
    944 		else
    945 		    {
    946 		    Player.p_mana -= MM_INCRMIGHT;
    947 		    Player.p_might +=
    948 			(1.2 * (Player.p_strength + Player.p_sword)
    949 			+ 5.0 - Player.p_might) / 2.0;
    950 		    mvprintw(5, 0, "New strength:  %.0f\n", Player.p_might);
    951 		    }
    952 		break;
    953 
    954 	    case '6':   /* invisible */
    955 		if (Player.p_magiclvl < ML_INVISIBLE)
    956 		    ILLSPELL();
    957 		else if (Player.p_mana < MM_INVISIBLE)
    958 		    NOMANA();
    959 		else
    960 		    {
    961 		    Player.p_mana -= MM_INVISIBLE;
    962 		    Player.p_speed +=
    963 			(1.2 * (Player.p_quickness + Player.p_quksilver)
    964 			+ 5.0 - Player.p_speed) / 2.0;
    965 		    mvprintw(5, 0, "New quickness:  %.0f\n", Player.p_speed);
    966 		    }
    967 		break;
    968 
    969 	    case '7':   /* transport */
    970 		if (Player.p_magiclvl < ML_XPORT)
    971 		    ILLSPELL();
    972 		else if (Player.p_mana < MM_XPORT)
    973 		    NOMANA();
    974 		else
    975 		    {
    976 		    Player.p_mana -= MM_XPORT;
    977 		    if (Player.p_brains + Player.p_magiclvl
    978 			< Curmonster.m_experience / 200.0 * drandom())
    979 			{
    980 			mvaddstr(5, 0, "Transport backfired!\n");
    981 			altercoordinates(0.0, 0.0, A_FAR);
    982 			cancelmonster();
    983 			}
    984 		    else
    985 			{
    986 			mvprintw(5, 0, "%s is transported.\n", Enemyname);
    987 			if (drandom() < 0.3)
    988 			    /* monster didn't drop its treasure */
    989 			    Curmonster.m_treasuretype = 0;
    990 
    991 			Curmonster.m_energy = 0.0;
    992 			}
    993 		    }
    994 		break;
    995 
    996 	    case '8':   /* paralyze */
    997 		if (Player.p_magiclvl < ML_PARALYZE)
    998 		    ILLSPELL();
    999 		else if (Player.p_mana < MM_PARALYZE)
   1000 		    NOMANA();
   1001 		else
   1002 		    {
   1003 		    Player.p_mana -= MM_PARALYZE;
   1004 		    if (Player.p_magiclvl >
   1005 			Curmonster.m_experience / 1000.0 * drandom())
   1006 			{
   1007 			mvprintw(5, 0, "%s is held.\n", Enemyname);
   1008 			Curmonster.m_speed = -2.0;
   1009 			}
   1010 		    else
   1011 			mvaddstr(5, 0, "Monster unaffected.\n");
   1012 		    }
   1013 		break;
   1014 
   1015 	    case '9':   /* specify */
   1016 		if (Player.p_specialtype < SC_COUNCIL)
   1017 		    ILLSPELL();
   1018 		else if (Player.p_mana < MM_SPECIFY)
   1019 		    NOMANA();
   1020 		else
   1021 		    {
   1022 		    Player.p_mana -= MM_SPECIFY;
   1023 		    mvaddstr(5, 0, "Which monster do you want [0-99] ? ");
   1024 		    Whichmonster = (int) infloat();
   1025 		    Whichmonster = MAX(0, MIN(99, Whichmonster));
   1026 		    longjmp(Fightenv, 0);
   1027 		    /*NOTREACHED*/
   1028 		    }
   1029 		break;
   1030 	    }
   1031 }
   1032 /**/
   1034 /************************************************************************
   1035 /
   1036 / FUNCTION NAME: callmonster()
   1037 /
   1038 / FUNCTION: read monster from file, and fill structure
   1039 /
   1040 / AUTHOR: E. A. Estes, 2/25/86
   1041 /
   1042 / ARGUMENTS:
   1043 /	int which - which monster to call
   1044 /
   1045 / RETURN VALUE: none
   1046 /
   1047 / MODULES CALLED: truncstring(), fread(), fseek(), floor(), drandom(),
   1048 /	strcpy()
   1049 /
   1050 / GLOBAL INPUTS: Curmonster, Circle, Player, *Monstfp
   1051 /
   1052 / GLOBAL OUTPUTS: Curmonster, Player, *Enemyname
   1053 /
   1054 / DESCRIPTION:
   1055 /	Read specified monster from monster database and fill up
   1056 /	current monster structure.
   1057 /	Adjust statistics based upon current size.
   1058 /	Handle some special monsters.
   1059 /
   1060 /************************************************************************/
   1061 
   1062 callmonster(which)
   1063 int	which;
   1064 {
   1065 struct monster	Othermonster;		/* to find a name for mimics */
   1066 
   1067     which = MIN(which, 99);		/* make sure within range */
   1068 
   1069     /* fill structure */
   1070     fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0);
   1071     fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
   1072 
   1073     /* handle some special monsters */
   1074     if (Curmonster.m_type == SM_MODNAR)
   1075 	{
   1076 	if (Player.p_specialtype < SC_COUNCIL)
   1077 	    /* randomize some stats */
   1078 	    {
   1079 	    Curmonster.m_strength *= drandom() + 0.5;
   1080 	    Curmonster.m_brains *= drandom() + 0.5;
   1081 	    Curmonster.m_speed *= drandom() + 0.5;
   1082 	    Curmonster.m_energy *= drandom() + 0.5;
   1083 	    Curmonster.m_experience *= drandom() + 0.5;
   1084 	    Curmonster.m_treasuretype =
   1085 		(int) ROLL(0.0, (double) Curmonster.m_treasuretype);
   1086 	    }
   1087 	else
   1088 	    /* make Modnar into Morgoth */
   1089 	    {
   1090 	    strcpy(Curmonster.m_name, "Morgoth");
   1091 	    Curmonster.m_strength = drandom() * (Player.p_maxenergy + Player.p_shield) / 1.4
   1092 		+ drandom() * (Player.p_maxenergy + Player.p_shield) / 1.5;
   1093 	    Curmonster.m_brains = Player.p_brains;
   1094 	    Curmonster.m_energy = Player.p_might * 30.0;
   1095 	    Curmonster.m_type = SM_MORGOTH;
   1096 	    Curmonster.m_speed = Player.p_speed * 1.1
   1097 		+ (Player.p_specialtype == SC_EXVALAR) ? Player.p_speed : 0.0;
   1098 	    Curmonster.m_flock = 0.0;
   1099 	    Curmonster.m_treasuretype = 0;
   1100 	    Curmonster.m_experience = 0.0;
   1101 	    }
   1102 	}
   1103     else if (Curmonster.m_type == SM_MIMIC)
   1104 	/* pick another name */
   1105 	{
   1106 	which = (int) ROLL(0.0, 100.0);
   1107 	fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0);
   1108 	fread(&Othermonster, SZ_MONSTERSTRUCT, 1, Monstfp);
   1109 	strcpy(Curmonster.m_name, Othermonster.m_name);
   1110 	}
   1111 
   1112     truncstring(Curmonster.m_name);
   1113 
   1114     if (Curmonster.m_type != SM_MORGOTH)
   1115 	/* adjust stats based on which circle player is in */
   1116 	{
   1117 	Curmonster.m_strength *= (1.0 + Circle / 2.0);
   1118 	Curmonster.m_brains *= Circle;
   1119 	Curmonster.m_speed += Circle * 1.e-9;
   1120 	Curmonster.m_energy *= Circle;
   1121 	Curmonster.m_experience *= Circle;
   1122 	}
   1123 
   1124     if (Player.p_blindness)
   1125 	/* cannot see monster if blind */
   1126 	Enemyname = "A monster";
   1127     else
   1128 	Enemyname = Curmonster.m_name;
   1129 
   1130     if (Player.p_speed <= 0.0)
   1131 	/* make Player.p_speed positive */
   1132 	{
   1133 	Curmonster.m_speed += -Player.p_speed;
   1134 	Player.p_speed = 1.0;
   1135 	}
   1136 
   1137     /* fill up the rest of the structure */
   1138     Curmonster.m_o_strength = Curmonster.m_strength;
   1139     Curmonster.m_o_speed = Curmonster.m_maxspeed = Curmonster.m_speed;
   1140     Curmonster.m_o_energy = Curmonster.m_energy;
   1141     Curmonster.m_melee = Curmonster.m_skirmish = 0.0;
   1142 }
   1143 /**/
   1145 /************************************************************************
   1146 /
   1147 / FUNCTION NAME: awardtreasure()
   1148 /
   1149 / FUNCTION: select a treasure
   1150 /
   1151 / AUTHOR: E. A. Estes, 12/4/85
   1152 /
   1153 / ARGUMENTS: none
   1154 /
   1155 / RETURN VALUE: none
   1156 /
   1157 / MODULES CALLED: pickmonster(), collecttaxes(), more(), cursedtreasure(),
   1158 /	floor(), wmove(), drandom(), sscanf(), printw(), altercoordinates(),
   1159 /	longjmp(), infloat(), waddstr(), getanswer(), getstring(), wclrtobot()
   1160 /
   1161 / GLOBAL INPUTS: Somebetter[], Curmonster, Whichmonster, Circle, Player,
   1162 /	*stdscr, Databuf[], *Statptr, Fightenv[]
   1163 /
   1164 / GLOBAL OUTPUTS: Whichmonster, Shield, Player
   1165 /
   1166 / DESCRIPTION:
   1167 /	Roll up a treasure based upon monster type and size, and
   1168 /	certain player statistics.
   1169 /	Handle cursed treasure.
   1170 /
   1171 /************************************************************************/
   1172 
   1173 awardtreasure()
   1174 {
   1175 register int	whichtreasure;		/* calculated treasure to grant */
   1176 int	temp;				/* temporary */
   1177 int	ch;				/* input */
   1178 double	treasuretype;			/* monster's treasure type */
   1179 double	gold = 0.0;			/* gold awarded */
   1180 double	gems = 0.0;			/* gems awarded */
   1181 double	dtemp;				/* for temporary calculations */
   1182 
   1183     whichtreasure = (int) ROLL(1.0, 3.0);	/* pick a treasure */
   1184     treasuretype = (double) Curmonster.m_treasuretype;
   1185 
   1186     move(4, 0);
   1187     clrtobot();
   1188     move(6, 0);
   1189 
   1190     if (drandom() > 0.65)
   1191 	/* gold and gems */
   1192 	{
   1193 	if (Curmonster.m_treasuretype > 7)
   1194 	    /* gems */
   1195 	    {
   1196 	    gems = ROLL(1.0, (treasuretype - 7.0)
   1197 		* (treasuretype - 7.0) * (Circle - 1.0) / 4.0);
   1198 	    printw("You have discovered %.0f gems!", gems);
   1199 	    }
   1200 	else
   1201 	    /* gold */
   1202 	    {
   1203 	    gold = ROLL(treasuretype * 10.0, treasuretype
   1204 		* treasuretype * 10.0 * (Circle - 1.0));
   1205 	    printw("You have found %.0f gold pieces.", gold);
   1206 	    }
   1207 
   1208 	addstr("  Do you want to pick them up ? ");
   1209 	ch = getanswer("NY", FALSE);
   1210 	addstr("\n\n");
   1211 
   1212 	if (ch == 'Y')
   1213 	    if (drandom() < treasuretype / 35.0 + 0.04)
   1214 		/* cursed */
   1215 		{
   1216 		addstr("They were cursed!\n");
   1217 		cursedtreasure();
   1218 		}
   1219 	    else
   1220 		collecttaxes(gold, gems);
   1221 
   1222 	return;
   1223 	}
   1224     else
   1225 	/* other treasures */
   1226 	{
   1227 	addstr("You have found some treasure.  Do you want to inspect it ? ");
   1228 	ch = getanswer("NY", FALSE);
   1229 	addstr("\n\n");
   1230 
   1231 	if (ch != 'Y')
   1232 	    return;
   1233 	else
   1234 	    if (drandom() < 0.08 && Curmonster.m_treasuretype != 4)
   1235 		{
   1236 		addstr("It was cursed!\n");
   1237 		cursedtreasure();
   1238 		return;
   1239 		}
   1240 	    else
   1241 		switch (Curmonster.m_treasuretype)
   1242 		    {
   1243 		    case 1:	/* treasure type 1 */
   1244 			switch (whichtreasure)
   1245 			    {
   1246 			    case 1:
   1247 				addstr("You've discovered a power booster!\n");
   1248 				Player.p_mana += ROLL(Circle * 4.0, Circle * 30.0);
   1249 				break;
   1250 
   1251 			    case 2:
   1252 				addstr("You have encountered a druid.\n");
   1253 				Player.p_experience +=
   1254 				    ROLL(0.0, 2000.0 + Circle * 400.0);
   1255 				break;
   1256 
   1257 			    case 3:
   1258 				addstr("You have found a holy orb.\n");
   1259 				Player.p_sin = MAX(0.0, Player.p_sin - 0.25);
   1260 				break;
   1261 			    }
   1262 			break;
   1263 		    /* end treasure type 1 */
   1264 
   1265 		    case 2:	/* treasure type 2 */
   1266 			switch (whichtreasure)
   1267 			    {
   1268 			    case 1:
   1269 				addstr("You have found an amulet.\n");
   1270 				++Player.p_amulets;
   1271 				break;
   1272 
   1273 			    case 2:
   1274 				addstr("You've found some holy water!\n");
   1275 				++Player.p_holywater;
   1276 				break;
   1277 
   1278 			    case 3:
   1279 				addstr("You've met a hermit!\n");
   1280 				Player.p_sin *= 0.75;
   1281 				Player.p_mana += 12.0 * Circle;
   1282 				break;
   1283 			    }
   1284 			break;
   1285 		    /* end treasure type 2 */
   1286 
   1287 		    case 3:	/* treasure type 3 */
   1288 			switch (whichtreasure)
   1289 			    {
   1290 			    case 1:
   1291 				dtemp = ROLL(7.0, 30.0 + Circle / 10.0);
   1292 				printw("You've found a +%.0f shield!\n", dtemp);
   1293 				if (dtemp >= Player.p_shield)
   1294 				    Player.p_shield = dtemp;
   1295 				else
   1296 				    SOMEBETTER();
   1297 				break;
   1298 
   1299 			    case 2:
   1300 				addstr("You have rescued a virgin.  Will you be honorable ? ");
   1301 				ch = getanswer("NY", FALSE);
   1302 				addstr("\n\n");
   1303 				if (ch == 'Y')
   1304 				    Player.p_virgin = TRUE;
   1305 				else
   1306 				    {
   1307 				    Player.p_experience += 2000.0 * Circle;
   1308 				    ++Player.p_sin;
   1309 				    }
   1310 				break;
   1311 
   1312 			    case 3:
   1313 				addstr("You've discovered some athelas!\n");
   1314 				--Player.p_poison;
   1315 				break;
   1316 			    }
   1317 			break;
   1318 		    /* end treasure type 3 */
   1319 
   1320 		    case 4:	/* treasure type 4 */
   1321 			addstr("You've found a scroll.  Will you read it ? ");
   1322 			ch = getanswer("NY", FALSE);
   1323 			addstr("\n\n");
   1324 
   1325 			if (ch == 'Y')
   1326 			    switch ((int) ROLL(1, 6))
   1327 				{
   1328 				case 1:
   1329 				    addstr("It throws up a shield for you next monster.\n");
   1330 				    getyx(stdscr, whichtreasure, ch);
   1331 				    more(whichtreasure);
   1332 				    Shield =
   1333 					(Player.p_maxenergy + Player.p_energy) * 5.5 + Circle * 50.0;
   1334 				    Whichmonster = pickmonster();
   1335 				    longjmp(Fightenv, 0);
   1336 				    /*NOTREACHED*/
   1337 
   1338 				case 2:
   1339 				    addstr("It makes you invisible for you next monster.\n");
   1340 				    getyx(stdscr, whichtreasure, ch);
   1341 				    more(whichtreasure);
   1342 				    Player.p_speed = 1e6;
   1343 				    Whichmonster = pickmonster();
   1344 				    longjmp(Fightenv, 0);
   1345 				    /*NOTREACHED*/
   1346 
   1347 				case 3:
   1348 				    addstr("It increases your strength ten fold to fight your next monster.\n");
   1349 				    getyx(stdscr, whichtreasure, ch);
   1350 				    more(whichtreasure);
   1351 				    Player.p_might *= 10.0;
   1352 				    Whichmonster = pickmonster();
   1353 				    longjmp(Fightenv, 0);
   1354 				    /*NOTREACHED*/
   1355 
   1356 				case 4:
   1357 				    addstr("It is a general knowledge scroll.\n");
   1358 				    Player.p_brains += ROLL(2.0, Circle);
   1359 				    Player.p_magiclvl += ROLL(1.0, Circle / 2.0);
   1360 				    break;
   1361 
   1362 				case 5:
   1363 				    addstr("It tells you how to pick your next monster.\n");
   1364 				    addstr("Which monster do you want [0-99] ? ");
   1365 				    Whichmonster = (int) infloat();
   1366 				    Whichmonster = MIN(99, MAX(0, Whichmonster));
   1367 				    longjmp(Fightenv, 0);
   1368 
   1369 				case 6:
   1370 				    addstr("It was cursed!\n");
   1371 				    cursedtreasure();
   1372 				    break;
   1373 				}
   1374 			    break;
   1375 		    /* end treasure type 4 */
   1376 
   1377 		    case 5:	/* treasure type 5 */
   1378 			switch (whichtreasure)
   1379 			    {
   1380 			    case 1:
   1381 				dtemp = ROLL(Circle / 4.0 + 5.0, Circle / 2.0 + 9.0);
   1382 				printw("You've discovered a +%.0f dagger.\n", dtemp);
   1383 				if (dtemp >= Player.p_sword)
   1384 				    Player.p_sword = dtemp;
   1385 				else
   1386 				    SOMEBETTER();
   1387 				break;
   1388 
   1389 			    case 2:
   1390 				dtemp = ROLL(7.5 + Circle * 3.0, Circle * 2.0 + 160.0);
   1391 				printw("You have found some +%.0f armour!\n", dtemp);
   1392 				if (dtemp >= Player.p_shield)
   1393 				    Player.p_shield = dtemp;
   1394 				else
   1395 				    SOMEBETTER();
   1396 				break;
   1397 
   1398 			    case 3:
   1399 				addstr("You've found a tablet.\n");
   1400 				Player.p_brains += 4.5 * Circle;
   1401 				break;
   1402 			    }
   1403 			break;
   1404 		    /* end treasure type 5 */
   1405 
   1406 		    case 6:	/* treasure type 6 */
   1407 			switch (whichtreasure)
   1408 			    {
   1409 			    case 1:
   1410 				addstr("You've found a priest.\n");
   1411 				Player.p_energy = Player.p_maxenergy + Player.p_shield;
   1412 				Player.p_sin /= 2.0;
   1413 				Player.p_mana += 24.0 * Circle;
   1414 				Player.p_brains += Circle;
   1415 				break;
   1416 
   1417 			    case 2:
   1418 				addstr("You have come upon Robin Hood!\n");
   1419 				Player.p_shield += Circle * 2.0;
   1420 				Player.p_strength += Circle / 2.5 + 1.0;
   1421 				break;
   1422 
   1423 			    case 3:
   1424 				dtemp = ROLL(2.0 + Circle / 4.0, Circle / 1.2 + 10.0);
   1425 				printw("You have found a +%.0f axe!\n", dtemp);
   1426 				if (dtemp >= Player.p_sword)
   1427 				    Player.p_sword = dtemp;
   1428 				else
   1429 				    SOMEBETTER();
   1430 				break;
   1431 			    }
   1432 			break;
   1433 		    /* end treasure type 6 */
   1434 
   1435 		    case 7:	/* treasure type 7 */
   1436 			switch (whichtreasure)
   1437 			    {
   1438 			    case 1:
   1439 				addstr("You've discovered a charm!\n");
   1440 				++Player.p_charms;
   1441 				break;
   1442 
   1443 			    case 2:
   1444 				addstr("You have encountered Merlyn!\n");
   1445 				Player.p_brains += Circle + 5.0;
   1446 				Player.p_magiclvl += Circle / 3.0 + 5.0;
   1447 				Player.p_mana += Circle * 10.0;
   1448 				break;
   1449 
   1450 			    case 3:
   1451 				dtemp = ROLL(5.0 + Circle / 3.0, Circle / 1.5 + 20.0);
   1452 				printw("You have found a +%.0f war hammer!\n", dtemp);
   1453 				if (dtemp >= Player.p_sword)
   1454 				    Player.p_sword = dtemp;
   1455 				else
   1456 				    SOMEBETTER();
   1457 				break;
   1458 			    }
   1459 			break;
   1460 		    /* end treasure type 7 */
   1461 
   1462 		    case 8:	/* treasure type 8 */
   1463 			switch (whichtreasure)
   1464 			    {
   1465 			    case 1:
   1466 				addstr("You have found a healing potion.\n");
   1467 				Player.p_poison = MIN(-2.0, Player.p_poison - 2.0);
   1468 				break;
   1469 
   1470 			    case 2:
   1471 				addstr("You have discovered a transporter.  Do you wish to go anywhere ? ");
   1472 				ch = getanswer("NY", FALSE);
   1473 				addstr("\n\n");
   1474 				if (ch == 'Y')
   1475 				    {
   1476 				    double x, y;
   1477 
   1478 				    addstr("X Y Coordinates ? ");
   1479 				    getstring(Databuf, SZ_DATABUF);
   1480 				    sscanf(Databuf, "%lf %lf", &x, &y);
   1481 				    altercoordinates(x, y, A_FORCED);
   1482 				    }
   1483 				break;
   1484 
   1485 			    case 3:
   1486 				dtemp = ROLL(10.0 + Circle / 1.2, Circle * 3.0 + 30.0);
   1487 				printw("You've found a +%.0f sword!\n", dtemp);
   1488 				if (dtemp >= Player.p_sword)
   1489 				    Player.p_sword = dtemp;
   1490 				else
   1491 				    SOMEBETTER();
   1492 				break;
   1493 			    }
   1494 			break;
   1495 		    /* end treasure type 8 */
   1496 
   1497 		    case 10:
   1498 		    case 11:
   1499 		    case 12:
   1500 		    case 13:	/* treasure types 10 - 13 */
   1501 			if (drandom() < 0.33)
   1502 			    {
   1503 			    if (Curmonster.m_treasuretype == 10)
   1504 				{
   1505 				addstr("You've found a pair of elven boots!\n");
   1506 				Player.p_quickness += 2.0;
   1507 				break;
   1508 				}
   1509 			    else if (Curmonster.m_treasuretype == 11
   1510 				&& !Player.p_palantir)
   1511 				{
   1512 				addstr("You've acquired Saruman's palantir.\n");
   1513 				Player.p_palantir = TRUE;
   1514 				break;
   1515 				}
   1516 			    else if (Player.p_ring.ring_type == R_NONE
   1517 				&& Player.p_specialtype < SC_COUNCIL
   1518 				&& (Curmonster.m_treasuretype == 12
   1519 				|| Curmonster.m_treasuretype == 13))
   1520 				/* roll up a ring */
   1521 				{
   1522 				if (drandom() < 0.8)
   1523 				    /* regular rings */
   1524 				    {
   1525 				    if (Curmonster.m_treasuretype == 12)
   1526 					{
   1527 					whichtreasure = R_NAZREG;
   1528 					temp = 35;
   1529 					}
   1530 				    else
   1531 					{
   1532 					whichtreasure = R_DLREG;
   1533 					temp = 0;
   1534 					}
   1535 				    }
   1536 				else
   1537 				    /* bad rings */
   1538 				    {
   1539 				    whichtreasure = R_BAD;
   1540 				    temp = 15 + Statptr->c_ringduration + (int) ROLL(0,5);
   1541 				    }
   1542 
   1543 				addstr("You've discovered a ring.  Will you pick it up ? ");
   1544 				ch = getanswer("NY", FALSE);
   1545 				addstr("\n\n");
   1546 
   1547 				if (ch == 'Y')
   1548 				    {
   1549 				    Player.p_ring.ring_type = whichtreasure;
   1550 				    Player.p_ring.ring_duration = temp;
   1551 				    }
   1552 
   1553 				break;
   1554 				}
   1555 			    }
   1556 			/* end treasure types 10 - 13 */
   1557 			/* fall through to treasure type 9 if no treasure from above */
   1558 
   1559 			case 9:	/* treasure type 9 */
   1560 			    switch (whichtreasure)
   1561 				{
   1562 				case 1:
   1563 				    if (Player.p_level <= 1000.0
   1564 					&& Player.p_crowns <= 3
   1565 					&& Player.p_level >= 10.0)
   1566 					{
   1567 					addstr("You have found a golden crown!\n");
   1568 					++Player.p_crowns;
   1569 					break;
   1570 					}
   1571 				    /* fall through otherwise */
   1572 
   1573 				case 2:
   1574 				    addstr("You've been blessed!\n");
   1575 				    Player.p_blessing = TRUE;
   1576 				    Player.p_sin /= 3.0;
   1577 				    Player.p_energy = Player.p_maxenergy + Player.p_shield;
   1578 				    Player.p_mana += 100.0 * Circle;
   1579 				    break;
   1580 
   1581 				case 3:
   1582 				    dtemp = ROLL(1.0, Circle / 5.0 + 5.0);
   1583 				    dtemp = MIN(dtemp, 99.0);
   1584 				    printw("You have discovered some +%.0f quicksilver!\n",dtemp);
   1585 				    if (dtemp >= Player.p_quksilver)
   1586 					Player.p_quksilver = dtemp;
   1587 				    else
   1588 					SOMEBETTER();
   1589 				    break;
   1590 				}
   1591 			    break;
   1592 		    /* end treasure type 9 */
   1593 		    }
   1594 	}
   1595 }
   1596 /**/
   1598 /************************************************************************
   1599 /
   1600 / FUNCTION NAME: cursedtreasure()
   1601 /
   1602 / FUNCTION: take care of cursed treasure
   1603 /
   1604 / AUTHOR: E. A. Estes, 12/4/85
   1605 /
   1606 / ARGUMENTS: none
   1607 /
   1608 / RETURN VALUE: none
   1609 /
   1610 / MODULES CALLED: waddstr()
   1611 /
   1612 / GLOBAL INPUTS: Player, *stdscr
   1613 /
   1614 / GLOBAL OUTPUTS: Player
   1615 /
   1616 / DESCRIPTION:
   1617 /	Handle cursed treasure.  Look for amulets and charms to save
   1618 /	the player from the curse.
   1619 /
   1620 /************************************************************************/
   1621 
   1622 cursedtreasure()
   1623 {
   1624     if (Player.p_charms > 0)
   1625 	{
   1626 	addstr("But your charm saved you!\n");
   1627 	--Player.p_charms;
   1628 	}
   1629     else if (Player.p_amulets > 0)
   1630 	{
   1631 	addstr("But your amulet saved you!\n");
   1632 	--Player.p_amulets;
   1633 	}
   1634     else
   1635 	{
   1636 	Player.p_energy = (Player.p_maxenergy + Player.p_shield) / 10.0;
   1637 	Player.p_poison += 0.25;
   1638 	}
   1639 }
   1640 /**/
   1642 /************************************************************************
   1643 /
   1644 / FUNCTION NAME: scramblestats()
   1645 /
   1646 / FUNCTION: scramble some selected statistics
   1647 /
   1648 / AUTHOR: E. A. Estes, 12/4/85
   1649 /
   1650 / ARGUMENTS: none
   1651 /
   1652 / RETURN VALUE: none
   1653 /
   1654 / MODULES CALLED: floor(), drandom()
   1655 /
   1656 / GLOBAL INPUTS: Player
   1657 /
   1658 / GLOBAL OUTPUTS: Player
   1659 /
   1660 / DESCRIPTION:
   1661 /	Swap a few player statistics randomly.
   1662 /
   1663 /************************************************************************/
   1664 
   1665 scramblestats()
   1666 {
   1667 double	dbuf[6];		/* to put statistic in */
   1668 double	dtemp1, dtemp2;		/* for swapping values */
   1669 register int	first, second;	/* indices for swapping */
   1670 register double  *dptr;		/* pointer for filling and emptying buf[] */
   1671 
   1672     /* fill buffer */
   1673     dptr = &dbuf[0];
   1674     *dptr++ = Player.p_strength;
   1675     *dptr++ = Player.p_mana;
   1676     *dptr++ = Player.p_brains;
   1677     *dptr++ = Player.p_magiclvl;
   1678     *dptr++ = Player.p_energy;
   1679     *dptr = Player.p_sin;
   1680 
   1681     /* pick values to swap */
   1682     first = (int) ROLL(0, 5);
   1683     second = (int) ROLL(0, 5);
   1684 
   1685     /* swap values */
   1686     dptr = &dbuf[0];
   1687     dtemp1 = dptr[first];
   1688     /* this expression is split to prevent a compiler loop on some compilers */
   1689     dtemp2 = dptr[second];
   1690     dptr[first] = dtemp2;
   1691     dptr[second] = dtemp1;
   1692 
   1693     /* empty buffer */
   1694     Player.p_strength = *dptr++;
   1695     Player.p_mana = *dptr++;
   1696     Player.p_brains = *dptr++;
   1697     Player.p_magiclvl = *dptr++;
   1698     Player.p_energy = *dptr++;
   1699     Player.p_sin = *dptr;
   1700 }
   1701