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