xref: /dragonfly/games/phantasia/fight.c (revision 333227be)
1 /*
2  * fight.c   Phantasia monster fighting routines
3  *
4  * $FreeBSD: src/games/phantasia/fight.c,v 1.7 1999/11/16 02:57:33 billf Exp $
5  * $DragonFly: src/games/phantasia/fight.c,v 1.2 2003/06/17 04:25:24 dillon Exp $
6  */
7 
8 #include <string.h>
9 #include "include.h"
10 
11 /************************************************************************
12 /
13 / FUNCTION NAME: encounter()
14 /
15 / FUNCTION: monster battle routine
16 /
17 / AUTHOR: E. A. Estes, 2/20/86
18 /
19 / ARGUMENTS:
20 /	int particular - particular monster to fight if >= 0
21 /
22 / RETURN VALUE: none
23 /
24 / MODULES CALLED: monsthits(), playerhits(), readmessage(), callmonster(),
25 /	writerecord(), pickmonster(), displaystats(), pow(), cancelmonster(),
26 /	awardtreasure(), more(), death(), wmove(), setjmp(), drandom(), printw(),
27 /	longjmp(), wrefresh(), mvprintw(), wclrtobot()
28 /
29 / GLOBAL INPUTS: Curmonster, Whichmonster, LINES, Lines, Circle, Shield,
30 /	Player, *stdscr, Fileloc, Fightenv[], *Enemyname
31 /
32 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player, Luckout
33 /
34 / DESCRIPTION:
35 /	Choose a monster and check against some special types.
36 /	Arbitrate between monster and player.  Watch for either
37 /	dying.
38 /
39 *************************************************************************/
40 
41 encounter(particular)
42 int	particular;
43 {
44 bool	firsthit = Player.p_blessing;	/* set if player gets the first hit */
45 int	flockcnt = 1;			/* how many time flocked */
46 
47     /* let others know what we are doing */
48     Player.p_status = S_MONSTER;
49     writerecord(&Player, Fileloc);
50 
51 #ifdef SYS5
52     flushinp();
53 #endif
54 
55     Shield = 0.0;		/* no shield up yet */
56 
57     if (particular >= 0)
58 	/* monster is specified */
59 	Whichmonster = particular;
60     else
61 	/* pick random monster */
62 	Whichmonster = pickmonster();
63 
64     setjmp(Fightenv);		/* this is to enable changing fight state */
65 
66     move(6, 0);
67     clrtobot();			/* clear bottom area of screen */
68 
69     Lines = 9;
70     callmonster(Whichmonster);	/* set up monster to fight */
71 
72     Luckout = FALSE;		/* haven't tried to luckout yet */
73 
74     if (Curmonster.m_type == SM_MORGOTH)
75 	mvprintw(4, 0, "You've encountered %s, Bane of the Council and Valar.\n",
76 	    Enemyname);
77 
78     if (Curmonster.m_type == SM_UNICORN)
79 	{
80 	if (Player.p_virgin)
81 	    {
82 	    printw("You just subdued %s, thanks to the virgin.\n", Enemyname);
83 	    Player.p_virgin = FALSE;
84 	    }
85 	else
86 	    {
87 	    printw("You just saw %s running away!\n", Enemyname);
88 	    Curmonster.m_experience = 0.0;
89 	    Curmonster.m_treasuretype = 0;
90 	    }
91 	}
92     else
93 	/* not a special monster */
94 	for (;;)
95 	    /* print header, and arbitrate between player and monster */
96 	    {
97 	    mvprintw(6, 0, "You are being attacked by %s,   EXP: %.0f   (Size: %.0f)\n",
98 		Enemyname, Curmonster.m_experience, Circle);
99 
100 	    displaystats();
101 	    mvprintw(1, 26, "%20.0f", Player.p_energy + Shield);	/* overprint energy */
102 	    readmessage();
103 
104 	    if (Curmonster.m_type == SM_DARKLORD
105 		&& Player.p_blessing
106 		&& Player.p_charms > 0)
107 		/* overpower Dark Lord with blessing and charm */
108 		{
109 		mvprintw(7, 0, "You just overpowered %s!", Enemyname);
110 		Lines = 8;
111 		Player.p_blessing = FALSE;
112 		--Player.p_charms;
113 		break;
114 		}
115 
116 	    /* allow paralyzed monster to wake up */
117 	    Curmonster.m_speed = MIN(Curmonster.m_speed + 1.0, Curmonster.m_maxspeed);
118 
119 	    if (drandom() * Curmonster.m_speed > drandom() * Player.p_speed
120 		/* monster is faster */
121 		&& Curmonster.m_type != SM_DARKLORD
122 		/* not D. L. */
123 		&& Curmonster.m_type != SM_SHRIEKER
124 		/* not mimic */
125 		&& !firsthit)
126 		/* monster gets a hit */
127 		monsthits();
128 	    else
129 		/* player gets a hit */
130 		{
131 		firsthit = FALSE;
132 		playerhits();
133 		}
134 
135 	    refresh();
136 
137 	    if (Lines > LINES - 2)
138 		/* near bottom of screen - pause */
139 		{
140 		more(Lines);
141 		move(Lines = 8, 0);
142 		clrtobot();
143 		}
144 
145 	    if (Player.p_energy <= 0.0)
146 		/* player died */
147 		{
148 		more(Lines);
149 		death(Enemyname);
150 		cancelmonster();
151 		break;		/* fight ends if the player is saved from death */
152 		}
153 
154 	    if (Curmonster.m_energy <= 0.0)
155 		/* monster died */
156 		break;
157 	    }
158 
159     /* give player credit for killing monster */
160     Player.p_experience += Curmonster.m_experience;
161 
162     if (drandom() < Curmonster.m_flock / 100.0)
163 	/* monster flocks */
164 	{
165 	more(Lines);
166 	++flockcnt;
167 	longjmp(Fightenv, 0);
168 	/*NOTREACHED*/
169 	}
170     else if (Circle > 1.0
171 	&& Curmonster.m_treasuretype > 0
172 	&& drandom() > 0.2 + pow(0.4, (double) (flockcnt / 3 + Circle / 3.0)))
173 	/* monster has treasure; this takes # of flocks and size into account */
174 	{
175 	more(Lines);
176 	awardtreasure();
177 	}
178 
179     /* pause before returning */
180     getyx(stdscr, Lines, flockcnt);
181     more(Lines + 1);
182 
183     Player.p_ring.ring_inuse = FALSE;	/* not using ring */
184 
185     /* clean up the screen */
186     move(4, 0);
187     clrtobot();
188 }
189 /**/
190 /************************************************************************
191 /
192 / FUNCTION NAME: pickmonster()
193 /
194 / FUNCTION: choose a monster based upon where we are
195 /
196 / AUTHOR: E. A. Estes, 2/20/86
197 /
198 / ARGUMENTS: none
199 /
200 / RETURN VALUE: monster number to call
201 /
202 / MODULES CALLED: floor(), drandom()
203 /
204 / GLOBAL INPUTS: Marsh, Circle, Player
205 /
206 / GLOBAL OUTPUTS: none
207 /
208 / DESCRIPTION:
209 /	Certain monsters can be found in certain areas of the grid.
210 /	We take care of rolling them here.
211 /	Unfortunately, this routine assumes that the monster data
212 /	base is arranged in a particular order.  If the data base
213 /	is altered (to add monsters, or make them tougher), this
214 /	routine may also need to be changed.
215 /
216 *************************************************************************/
217 
218 pickmonster()
219 {
220     if (Player.p_specialtype == SC_VALAR)
221 	/* even chance of any monster */
222 	return((int) ROLL(0.0, 100.0));
223 
224     if (Marsh)
225 	/* water monsters */
226 	return((int) ROLL(0.0, 15.0));
227 
228     else if (Circle > 24)
229 	/* even chance of all non-water monsters */
230 	return((int) ROLL(14.0, 86.0));
231 
232     else if (Circle > 15)
233 	/* chance of all non-water monsters, weighted toward middle */
234 	return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 37.0)));
235 
236     else if (Circle > 8)
237 	/* not all non-water monsters, weighted toward middle */
238 	return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 26.0)));
239 
240     else if (Circle > 3)
241 	/* even chance of some tamer non-water monsters */
242 	return((int) ROLL(14.0, 50.0));
243 
244     else
245 	/* even chance of some of the tamest non-water monsters */
246 	return((int) ROLL(14.0, 25.0));
247 }
248 /**/
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 
290     if (Player.p_ring.ring_type != R_NONE)
291 	/* player has a ring */
292 	addstr("7:Use Ring  ");
293     else
294 	clrtoeol();
295 
296     ch = inputoption();
297 
298     move(8, 0);
299     clrtobot();			/* clear any messages from before */
300     Lines = 9;
301     mvaddstr(4, 0, "\n\n");	/* clear status area */
302 
303     switch (ch)
304 	{
305 	case 'T':		/* timeout; lose turn */
306 	    break;
307 
308 	case ' ':
309 	case '1':		/* melee */
310 	    /* melee affects monster's energy and strength */
311 	    inflict = ROLL(Player.p_might / 2.0 + 5.0, 1.3 * Player.p_might)
312 		+ (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
313 
314 	    Curmonster.m_melee += inflict;
315 	    Curmonster.m_strength = Curmonster.m_o_strength
316 		- Curmonster.m_melee / Curmonster.m_o_energy
317 		* Curmonster.m_o_strength / 4.0;
318 	    hitmonster(inflict);
319 	    break;
320 
321 	case '2':		/* skirmish */
322 	    /* skirmish affects monter's energy and speed */
323 	    inflict = ROLL(Player.p_might / 3.0 + 3.0, 1.1 * Player.p_might)
324 		+ (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
325 
326 	    Curmonster.m_skirmish += inflict;
327 	    Curmonster.m_maxspeed = Curmonster.m_o_speed
328 		- Curmonster.m_skirmish / Curmonster.m_o_energy
329 		* Curmonster.m_o_speed / 4.0;
330 	    hitmonster(inflict);
331 	    break;
332 
333 	case '3':		/* evade */
334 	    /* use brains and speed to try to evade */
335 	    if ((Curmonster.m_type == SM_DARKLORD
336 		|| Curmonster.m_type == SM_SHRIEKER
337 		/* can always run from D. L. and shrieker */
338 		|| drandom() * Player.p_speed * Player.p_brains
339 		    > drandom() * Curmonster.m_speed * Curmonster.m_brains)
340 		&& (Curmonster.m_type != SM_MIMIC))
341 		/* cannot run from mimic */
342 		{
343 		mvaddstr(Lines++, 0, "You got away!");
344 		cancelmonster();
345 		altercoordinates(0.0, 0.0, A_NEAR);
346 		}
347 	    else
348 		mvprintw(Lines++, 0, "%s is still after you!", Enemyname);
349 
350 	    break;
351 
352 	case 'M':
353 	case '4':		/* magic spell */
354 	    throwspell();
355 	    break;
356 
357 	case '5':		/* nick */
358 	    /* hit 1 plus sword; give some experience */
359 	    inflict = 1.0 + Player.p_sword;
360 	    Player.p_experience += floor(Curmonster.m_experience / 10.0);
361 	    Curmonster.m_experience *= 0.92;
362 	    /* monster gets meaner */
363 	    Curmonster.m_maxspeed += 2.0;
364 	    Curmonster.m_speed = (Curmonster.m_speed < 0.0) ? 0.0 : Curmonster.m_speed + 2.0;
365 	    if (Curmonster.m_type == SM_DARKLORD)
366 		/* Dark Lord; doesn't like to be nicked */
367 		{
368 		mvprintw(Lines++, 0,
369 		    "You hit %s %.0f times, and made him mad!", Enemyname, inflict);
370 		Player.p_quickness /= 2.0;
371 		altercoordinates(0.0, 0.0, A_FAR);
372 		cancelmonster();
373 		}
374 	    else
375 		hitmonster(inflict);
376 	    break;
377 
378 	case 'B':
379 	case '6':	/* luckout */
380 	    if (Luckout)
381 		mvaddstr(Lines++, 0, "You already tried that.");
382 	    else
383 		{
384 		Luckout = TRUE;
385 		if (Curmonster.m_type == SM_MORGOTH)
386 		    /* Morgoth; ally */
387 		    {
388 		    if (drandom() < Player.p_sin / 100.0)
389 			{
390 			mvprintw(Lines++, 0, "%s accepted!", Enemyname);
391 			cancelmonster();
392 			}
393 		    else
394 			mvaddstr(Lines++, 0, "Nope, he's not interested.");
395 		    }
396 		else
397 		    /* normal monster; use brains for success */
398 		    {
399 		    if ((drandom() + 0.333) * Player.p_brains
400 			< (drandom() + 0.333) * Curmonster.m_brains)
401 			mvprintw(Lines++, 0, "You blew it, %s.", Player.p_name);
402 		    else
403 			{
404 			mvaddstr(Lines++, 0, "You made it!");
405 			Curmonster.m_energy = 0.0;
406 			}
407 		    }
408 		}
409 	    break;
410 
411 	case '7':		/* use ring */
412 	    if (Player.p_ring.ring_type != R_NONE)
413 		{
414 		mvaddstr(Lines++, 0, "Now using ring.");
415 		Player.p_ring.ring_inuse = TRUE;
416 		if (Player.p_ring.ring_type != R_DLREG)
417 		    /* age ring */
418 		    --Player.p_ring.ring_duration;
419 		}
420 	    break;
421 	}
422 
423 }
424 /**/
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 /**/
706 /************************************************************************
707 /
708 / FUNCTION NAME: cancelmonster()
709 /
710 / FUNCTION: mark current monster as no longer active
711 /
712 / AUTHOR: E. A. Estes, 12/4/85
713 /
714 / ARGUMENTS: none
715 /
716 / RETURN VALUE: none
717 /
718 / MODULES CALLED: none
719 /
720 / GLOBAL INPUTS: none
721 /
722 / GLOBAL OUTPUTS: Curmonster
723 /
724 / DESCRIPTION:
725 /	Clear current monster's energy, experience, treasure type, and
726 /	flock.  This is the same as having the monster run away.
727 /
728 *************************************************************************/
729 
730 cancelmonster()
731 {
732     Curmonster.m_energy = 0.0;
733     Curmonster.m_experience = 0.0;
734     Curmonster.m_treasuretype = 0;
735     Curmonster.m_flock = 0.0;
736 }
737 /**/
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 /**/
792 /************************************************************************
793 /
794 / FUNCTION NAME: throwspell()
795 /
796 / FUNCTION: throw a magic spell
797 /
798 / AUTHOR: E. A. Estes, 12/4/85
799 /
800 / ARGUMENTS: none
801 /
802 / RETURN VALUE: none
803 /
804 / MODULES CALLED: hitmonster(), cancelmonster(), sqrt(), floor(), wmove(),
805 /	drandom(), altercoordinates(), longjmp(), infloat(), waddstr(), mvprintw(),
806 /	getanswer()
807 /
808 / GLOBAL INPUTS: Curmonster, Whichmonster, Nomana[], Player, *stdscr,
809 /	Fightenv[], Illspell[], *Enemyname
810 /
811 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Shield, Player
812 /
813 / DESCRIPTION:
814 /	Prompt player and process magic spells.
815 /
816 *************************************************************************/
817 
818 throwspell()
819 {
820 double	inflict;	/* damage inflicted */
821 double	dtemp;		/* for dtemporary calculations */
822 int	ch;		/* input */
823 
824     mvaddstr(7, 0, "\n\n");		/* clear menu area */
825 
826     if (Player.p_magiclvl >= ML_ALLORNOTHING)
827 	mvaddstr(7, 0, "1:All or Nothing  ");
828     if (Player.p_magiclvl >= ML_MAGICBOLT)
829 	addstr("2:Magic Bolt  ");
830     if (Player.p_magiclvl >= ML_FORCEFIELD)
831 	addstr("3:Force Field  ");
832     if (Player.p_magiclvl >= ML_XFORM)
833 	addstr("4:Transform  ");
834     if (Player.p_magiclvl >= ML_INCRMIGHT)
835 	addstr("5:Increase Might\n");
836     if (Player.p_magiclvl >= ML_INVISIBLE)
837 	mvaddstr(8, 0, "6:Invisibility  ");
838     if (Player.p_magiclvl >= ML_XPORT)
839 	addstr("7:Transport  ");
840     if (Player.p_magiclvl >= ML_PARALYZE)
841 	addstr("8:Paralyze  ");
842     if (Player.p_specialtype >= SC_COUNCIL)
843 	addstr("9:Specify");
844     mvaddstr(4, 0, "Spell ? ");
845 
846     ch = getanswer(" ", TRUE);
847 
848     mvaddstr(7, 0, "\n\n");		/* clear menu area */
849 
850     if (Curmonster.m_type == SM_MORGOTH && ch != '3')
851 	/* can only throw force field against Morgoth */
852 	ILLSPELL();
853     else
854 	switch (ch)
855 	    {
856 	    case '1':   /* all or nothing */
857 		if (drandom() < 0.25)
858 		    /* success */
859 		    {
860 		    inflict = Curmonster.m_energy * 1.01 + 1.0;
861 
862 		    if (Curmonster.m_type == SM_DARKLORD)
863 			/* all or nothing doesn't quite work against D. L. */
864 			inflict *= 0.9;
865 		    }
866 		else
867 		    /* failure -- monster gets stronger and quicker */
868 		    {
869 		    Curmonster.m_o_strength = Curmonster.m_strength *= 2.0;
870 		    Curmonster.m_maxspeed *= 2.0;
871 		    Curmonster.m_o_speed *= 2.0;
872 
873 		    /* paralyzed monsters wake up a bit */
874 		    Curmonster.m_speed = MAX(1.0, Curmonster.m_speed * 2.0);
875 		    }
876 
877 		if (Player.p_mana >= MM_ALLORNOTHING)
878 		    /* take a mana if player has one */
879 		    Player.p_mana -= MM_ALLORNOTHING;
880 
881 		hitmonster(inflict);
882 		break;
883 
884 	    case '2':   /* magic bolt */
885 		if (Player.p_magiclvl < ML_MAGICBOLT)
886 		    ILLSPELL();
887 		else
888 		    {
889 		    do
890 			/* prompt for amount to expend */
891 			{
892 			mvaddstr(4, 0, "How much mana for bolt? ");
893 			dtemp = floor(infloat());
894 			}
895 		    while (dtemp < 0.0 || dtemp > Player.p_mana);
896 
897 		    Player.p_mana -= dtemp;
898 
899 		    if (Curmonster.m_type == SM_DARKLORD)
900 			/* magic bolts don't work against D. L. */
901 			inflict = 0.0;
902 		    else
903 			inflict = dtemp * ROLL(15.0, sqrt(Player.p_magiclvl / 3.0 + 1.0));
904 		    mvaddstr(5, 0, "Magic Bolt fired!\n");
905 		    hitmonster(inflict);
906 		    }
907 		break;
908 
909 	    case '3':   /* force field */
910 		if (Player.p_magiclvl < ML_FORCEFIELD)
911 		    ILLSPELL();
912 		else if (Player.p_mana < MM_FORCEFIELD)
913 		    NOMANA();
914 		else
915 		    {
916 		    Player.p_mana -= MM_FORCEFIELD;
917 		    Shield = (Player.p_maxenergy + Player.p_shield) * 4.2 + 45.0;
918 		    mvaddstr(5, 0, "Force Field up.\n");
919 		    }
920 		break;
921 
922 	    case '4':   /* transform */
923 		if (Player.p_magiclvl < ML_XFORM)
924 		    ILLSPELL();
925 		else if (Player.p_mana < MM_XFORM)
926 		    NOMANA();
927 		else
928 		    {
929 		    Player.p_mana -= MM_XFORM;
930 		    Whichmonster = (int) ROLL(0.0, 100.0);
931 		    longjmp(Fightenv, 0);
932 		    /*NOTREACHED*/
933 		    }
934 		break;
935 
936 	    case '5':   /* increase might */
937 		if (Player.p_magiclvl < ML_INCRMIGHT)
938 		    ILLSPELL();
939 		else if (Player.p_mana < MM_INCRMIGHT)
940 		    NOMANA();
941 		else
942 		    {
943 		    Player.p_mana -= MM_INCRMIGHT;
944 		    Player.p_might +=
945 			(1.2 * (Player.p_strength + Player.p_sword)
946 			+ 5.0 - Player.p_might) / 2.0;
947 		    mvprintw(5, 0, "New strength:  %.0f\n", Player.p_might);
948 		    }
949 		break;
950 
951 	    case '6':   /* invisible */
952 		if (Player.p_magiclvl < ML_INVISIBLE)
953 		    ILLSPELL();
954 		else if (Player.p_mana < MM_INVISIBLE)
955 		    NOMANA();
956 		else
957 		    {
958 		    Player.p_mana -= MM_INVISIBLE;
959 		    Player.p_speed +=
960 			(1.2 * (Player.p_quickness + Player.p_quksilver)
961 			+ 5.0 - Player.p_speed) / 2.0;
962 		    mvprintw(5, 0, "New quickness:  %.0f\n", Player.p_speed);
963 		    }
964 		break;
965 
966 	    case '7':   /* transport */
967 		if (Player.p_magiclvl < ML_XPORT)
968 		    ILLSPELL();
969 		else if (Player.p_mana < MM_XPORT)
970 		    NOMANA();
971 		else
972 		    {
973 		    Player.p_mana -= MM_XPORT;
974 		    if (Player.p_brains + Player.p_magiclvl
975 			< Curmonster.m_experience / 200.0 * drandom())
976 			{
977 			mvaddstr(5, 0, "Transport backfired!\n");
978 			altercoordinates(0.0, 0.0, A_FAR);
979 			cancelmonster();
980 			}
981 		    else
982 			{
983 			mvprintw(5, 0, "%s is transported.\n", Enemyname);
984 			if (drandom() < 0.3)
985 			    /* monster didn't drop its treasure */
986 			    Curmonster.m_treasuretype = 0;
987 
988 			Curmonster.m_energy = 0.0;
989 			}
990 		    }
991 		break;
992 
993 	    case '8':   /* paralyze */
994 		if (Player.p_magiclvl < ML_PARALYZE)
995 		    ILLSPELL();
996 		else if (Player.p_mana < MM_PARALYZE)
997 		    NOMANA();
998 		else
999 		    {
1000 		    Player.p_mana -= MM_PARALYZE;
1001 		    if (Player.p_magiclvl >
1002 			Curmonster.m_experience / 1000.0 * drandom())
1003 			{
1004 			mvprintw(5, 0, "%s is held.\n", Enemyname);
1005 			Curmonster.m_speed = -2.0;
1006 			}
1007 		    else
1008 			mvaddstr(5, 0, "Monster unaffected.\n");
1009 		    }
1010 		break;
1011 
1012 	    case '9':   /* specify */
1013 		if (Player.p_specialtype < SC_COUNCIL)
1014 		    ILLSPELL();
1015 		else if (Player.p_mana < MM_SPECIFY)
1016 		    NOMANA();
1017 		else
1018 		    {
1019 		    Player.p_mana -= MM_SPECIFY;
1020 		    mvaddstr(5, 0, "Which monster do you want [0-99] ? ");
1021 		    Whichmonster = (int) infloat();
1022 		    Whichmonster = MAX(0, MIN(99, Whichmonster));
1023 		    longjmp(Fightenv, 0);
1024 		    /*NOTREACHED*/
1025 		    }
1026 		break;
1027 	    }
1028 }
1029 /**/
1030 /************************************************************************
1031 /
1032 / FUNCTION NAME: callmonster()
1033 /
1034 / FUNCTION: read monster from file, and fill structure
1035 /
1036 / AUTHOR: E. A. Estes, 2/25/86
1037 /
1038 / ARGUMENTS:
1039 /	int which - which monster to call
1040 /
1041 / RETURN VALUE: none
1042 /
1043 / MODULES CALLED: truncstring(), fread(), fseek(), floor(), drandom(),
1044 /	strcpy()
1045 /
1046 / GLOBAL INPUTS: Curmonster, Circle, Player, *Monstfp
1047 /
1048 / GLOBAL OUTPUTS: Curmonster, Player, *Enemyname
1049 /
1050 / DESCRIPTION:
1051 /	Read specified monster from monster database and fill up
1052 /	current monster structure.
1053 /	Adjust statistics based upon current size.
1054 /	Handle some special monsters.
1055 /
1056 *************************************************************************/
1057 
1058 callmonster(which)
1059 int	which;
1060 {
1061 struct monster	Othermonster;		/* to find a name for mimics */
1062 
1063     which = MIN(which, 99);		/* make sure within range */
1064 
1065     /* fill structure */
1066     fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0);
1067     fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
1068 
1069     /* handle some special monsters */
1070     if (Curmonster.m_type == SM_MODNAR)
1071 	{
1072 	if (Player.p_specialtype < SC_COUNCIL)
1073 	    /* randomize some stats */
1074 	    {
1075 	    Curmonster.m_strength *= drandom() + 0.5;
1076 	    Curmonster.m_brains *= drandom() + 0.5;
1077 	    Curmonster.m_speed *= drandom() + 0.5;
1078 	    Curmonster.m_energy *= drandom() + 0.5;
1079 	    Curmonster.m_experience *= drandom() + 0.5;
1080 	    Curmonster.m_treasuretype =
1081 		(int) ROLL(0.0, (double) Curmonster.m_treasuretype);
1082 	    }
1083 	else
1084 	    /* make Modnar into Morgoth */
1085 	    {
1086 	    strcpy(Curmonster.m_name, "Morgoth");
1087 	    Curmonster.m_strength = drandom() * (Player.p_maxenergy + Player.p_shield) / 1.4
1088 		+ drandom() * (Player.p_maxenergy + Player.p_shield) / 1.5;
1089 	    Curmonster.m_brains = Player.p_brains;
1090 	    Curmonster.m_energy = Player.p_might * 30.0;
1091 	    Curmonster.m_type = SM_MORGOTH;
1092 	    Curmonster.m_speed = Player.p_speed * 1.1
1093 		+ (Player.p_specialtype == SC_EXVALAR) ? Player.p_speed : 0.0;
1094 	    Curmonster.m_flock = 0.0;
1095 	    Curmonster.m_treasuretype = 0;
1096 	    Curmonster.m_experience = 0.0;
1097 	    }
1098 	}
1099     else if (Curmonster.m_type == SM_MIMIC)
1100 	/* pick another name */
1101 	{
1102 	which = (int) ROLL(0.0, 100.0);
1103 	fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0);
1104 	fread(&Othermonster, SZ_MONSTERSTRUCT, 1, Monstfp);
1105 	strcpy(Curmonster.m_name, Othermonster.m_name);
1106 	}
1107 
1108     truncstring(Curmonster.m_name);
1109 
1110     if (Curmonster.m_type != SM_MORGOTH)
1111 	/* adjust stats based on which circle player is in */
1112 	{
1113 	Curmonster.m_strength *= (1.0 + Circle / 2.0);
1114 	Curmonster.m_brains *= Circle;
1115 	Curmonster.m_speed += Circle * 1.e-9;
1116 	Curmonster.m_energy *= Circle;
1117 	Curmonster.m_experience *= Circle;
1118 	}
1119 
1120     if (Player.p_blindness)
1121 	/* cannot see monster if blind */
1122 	Enemyname = "A monster";
1123     else
1124 	Enemyname = Curmonster.m_name;
1125 
1126     if (Player.p_speed <= 0.0)
1127 	/* make Player.p_speed positive */
1128 	{
1129 	Curmonster.m_speed += -Player.p_speed;
1130 	Player.p_speed = 1.0;
1131 	}
1132 
1133     /* fill up the rest of the structure */
1134     Curmonster.m_o_strength = Curmonster.m_strength;
1135     Curmonster.m_o_speed = Curmonster.m_maxspeed = Curmonster.m_speed;
1136     Curmonster.m_o_energy = Curmonster.m_energy;
1137     Curmonster.m_melee = Curmonster.m_skirmish = 0.0;
1138 }
1139 /**/
1140 /************************************************************************
1141 /
1142 / FUNCTION NAME: awardtreasure()
1143 /
1144 / FUNCTION: select a treasure
1145 /
1146 / AUTHOR: E. A. Estes, 12/4/85
1147 /
1148 / ARGUMENTS: none
1149 /
1150 / RETURN VALUE: none
1151 /
1152 / MODULES CALLED: pickmonster(), collecttaxes(), more(), cursedtreasure(),
1153 /	floor(), wmove(), drandom(), sscanf(), printw(), altercoordinates(),
1154 /	longjmp(), infloat(), waddstr(), getanswer(), getstring(), wclrtobot()
1155 /
1156 / GLOBAL INPUTS: Somebetter[], Curmonster, Whichmonster, Circle, Player,
1157 /	*stdscr, Databuf[], *Statptr, Fightenv[]
1158 /
1159 / GLOBAL OUTPUTS: Whichmonster, Shield, Player
1160 /
1161 / DESCRIPTION:
1162 /	Roll up a treasure based upon monster type and size, and
1163 /	certain player statistics.
1164 /	Handle cursed treasure.
1165 /
1166 *************************************************************************/
1167 
1168 awardtreasure()
1169 {
1170 int	whichtreasure;		/* calculated treasure to grant */
1171 int	temp;				/* temporary */
1172 int	ch;				/* input */
1173 double	treasuretype;			/* monster's treasure type */
1174 double	gold = 0.0;			/* gold awarded */
1175 double	gems = 0.0;			/* gems awarded */
1176 double	dtemp;				/* for temporary calculations */
1177 
1178     whichtreasure = (int) ROLL(1.0, 3.0);	/* pick a treasure */
1179     treasuretype = (double) Curmonster.m_treasuretype;
1180 
1181     move(4, 0);
1182     clrtobot();
1183     move(6, 0);
1184 
1185     if (drandom() > 0.65)
1186 	/* gold and gems */
1187 	{
1188 	if (Curmonster.m_treasuretype > 7)
1189 	    /* gems */
1190 	    {
1191 	    gems = ROLL(1.0, (treasuretype - 7.0)
1192 		* (treasuretype - 7.0) * (Circle - 1.0) / 4.0);
1193 	    printw("You have discovered %.0f gems!", gems);
1194 	    }
1195 	else
1196 	    /* gold */
1197 	    {
1198 	    gold = ROLL(treasuretype * 10.0, treasuretype
1199 		* treasuretype * 10.0 * (Circle - 1.0));
1200 	    printw("You have found %.0f gold pieces.", gold);
1201 	    }
1202 
1203 	addstr("  Do you want to pick them up ? ");
1204 	ch = getanswer("NY", FALSE);
1205 	addstr("\n\n");
1206 
1207 	if (ch == 'Y') {
1208 	    if (drandom() < treasuretype / 35.0 + 0.04)
1209 		/* cursed */
1210 		{
1211 		addstr("They were cursed!\n");
1212 		cursedtreasure();
1213 		}
1214 	    else
1215 		collecttaxes(gold, gems);
1216 	}
1217 
1218 	return;
1219 	}
1220     else
1221 	/* other treasures */
1222 	{
1223 	addstr("You have found some treasure.  Do you want to inspect it ? ");
1224 	ch = getanswer("NY", FALSE);
1225 	addstr("\n\n");
1226 
1227 	if (ch != 'Y')
1228 	    return;
1229 	else
1230 	    if (drandom() < 0.08 && Curmonster.m_treasuretype != 4)
1231 		{
1232 		addstr("It was cursed!\n");
1233 		cursedtreasure();
1234 		return;
1235 		}
1236 	    else
1237 		switch (Curmonster.m_treasuretype)
1238 		    {
1239 		    case 1:	/* treasure type 1 */
1240 			switch (whichtreasure)
1241 			    {
1242 			    case 1:
1243 				addstr("You've discovered a power booster!\n");
1244 				Player.p_mana += ROLL(Circle * 4.0, Circle * 30.0);
1245 				break;
1246 
1247 			    case 2:
1248 				addstr("You have encountered a druid.\n");
1249 				Player.p_experience +=
1250 				    ROLL(0.0, 2000.0 + Circle * 400.0);
1251 				break;
1252 
1253 			    case 3:
1254 				addstr("You have found a holy orb.\n");
1255 				Player.p_sin = MAX(0.0, Player.p_sin - 0.25);
1256 				break;
1257 			    }
1258 			break;
1259 		    /* end treasure type 1 */
1260 
1261 		    case 2:	/* treasure type 2 */
1262 			switch (whichtreasure)
1263 			    {
1264 			    case 1:
1265 				addstr("You have found an amulet.\n");
1266 				++Player.p_amulets;
1267 				break;
1268 
1269 			    case 2:
1270 				addstr("You've found some holy water!\n");
1271 				++Player.p_holywater;
1272 				break;
1273 
1274 			    case 3:
1275 				addstr("You've met a hermit!\n");
1276 				Player.p_sin *= 0.75;
1277 				Player.p_mana += 12.0 * Circle;
1278 				break;
1279 			    }
1280 			break;
1281 		    /* end treasure type 2 */
1282 
1283 		    case 3:	/* treasure type 3 */
1284 			switch (whichtreasure)
1285 			    {
1286 			    case 1:
1287 				dtemp = ROLL(7.0, 30.0 + Circle / 10.0);
1288 				printw("You've found a +%.0f shield!\n", dtemp);
1289 				if (dtemp >= Player.p_shield)
1290 				    Player.p_shield = dtemp;
1291 				else
1292 				    SOMEBETTER();
1293 				break;
1294 
1295 			    case 2:
1296 				addstr("You have rescued a virgin.  Will you be honorable ? ");
1297 				ch = getanswer("NY", FALSE);
1298 				addstr("\n\n");
1299 				if (ch == 'Y')
1300 				    Player.p_virgin = TRUE;
1301 				else
1302 				    {
1303 				    Player.p_experience += 2000.0 * Circle;
1304 				    ++Player.p_sin;
1305 				    }
1306 				break;
1307 
1308 			    case 3:
1309 				addstr("You've discovered some athelas!\n");
1310 				--Player.p_poison;
1311 				break;
1312 			    }
1313 			break;
1314 		    /* end treasure type 3 */
1315 
1316 		    case 4:	/* treasure type 4 */
1317 			addstr("You've found a scroll.  Will you read it ? ");
1318 			ch = getanswer("NY", FALSE);
1319 			addstr("\n\n");
1320 
1321 			if (ch == 'Y')
1322 			    switch ((int) ROLL(1, 6))
1323 				{
1324 				case 1:
1325 				    addstr("It throws up a shield for you next monster.\n");
1326 				    getyx(stdscr, whichtreasure, ch);
1327 				    more(whichtreasure);
1328 				    Shield =
1329 					(Player.p_maxenergy + Player.p_energy) * 5.5 + Circle * 50.0;
1330 				    Whichmonster = pickmonster();
1331 				    longjmp(Fightenv, 0);
1332 				    /*NOTREACHED*/
1333 
1334 				case 2:
1335 				    addstr("It makes you invisible for you next monster.\n");
1336 				    getyx(stdscr, whichtreasure, ch);
1337 				    more(whichtreasure);
1338 				    Player.p_speed = 1e6;
1339 				    Whichmonster = pickmonster();
1340 				    longjmp(Fightenv, 0);
1341 				    /*NOTREACHED*/
1342 
1343 				case 3:
1344 				    addstr("It increases your strength ten fold to fight your next monster.\n");
1345 				    getyx(stdscr, whichtreasure, ch);
1346 				    more(whichtreasure);
1347 				    Player.p_might *= 10.0;
1348 				    Whichmonster = pickmonster();
1349 				    longjmp(Fightenv, 0);
1350 				    /*NOTREACHED*/
1351 
1352 				case 4:
1353 				    addstr("It is a general knowledge scroll.\n");
1354 				    Player.p_brains += ROLL(2.0, Circle);
1355 				    Player.p_magiclvl += ROLL(1.0, Circle / 2.0);
1356 				    break;
1357 
1358 				case 5:
1359 				    addstr("It tells you how to pick your next monster.\n");
1360 				    addstr("Which monster do you want [0-99] ? ");
1361 				    Whichmonster = (int) infloat();
1362 				    Whichmonster = MIN(99, MAX(0, Whichmonster));
1363 				    longjmp(Fightenv, 0);
1364 
1365 				case 6:
1366 				    addstr("It was cursed!\n");
1367 				    cursedtreasure();
1368 				    break;
1369 				}
1370 			    break;
1371 		    /* end treasure type 4 */
1372 
1373 		    case 5:	/* treasure type 5 */
1374 			switch (whichtreasure)
1375 			    {
1376 			    case 1:
1377 				dtemp = ROLL(Circle / 4.0 + 5.0, Circle / 2.0 + 9.0);
1378 				printw("You've discovered a +%.0f dagger.\n", dtemp);
1379 				if (dtemp >= Player.p_sword)
1380 				    Player.p_sword = dtemp;
1381 				else
1382 				    SOMEBETTER();
1383 				break;
1384 
1385 			    case 2:
1386 				dtemp = ROLL(7.5 + Circle * 3.0, Circle * 2.0 + 160.0);
1387 				printw("You have found some +%.0f armour!\n", dtemp);
1388 				if (dtemp >= Player.p_shield)
1389 				    Player.p_shield = dtemp;
1390 				else
1391 				    SOMEBETTER();
1392 				break;
1393 
1394 			    case 3:
1395 				addstr("You've found a tablet.\n");
1396 				Player.p_brains += 4.5 * Circle;
1397 				break;
1398 			    }
1399 			break;
1400 		    /* end treasure type 5 */
1401 
1402 		    case 6:	/* treasure type 6 */
1403 			switch (whichtreasure)
1404 			    {
1405 			    case 1:
1406 				addstr("You've found a priest.\n");
1407 				Player.p_energy = Player.p_maxenergy + Player.p_shield;
1408 				Player.p_sin /= 2.0;
1409 				Player.p_mana += 24.0 * Circle;
1410 				Player.p_brains += Circle;
1411 				break;
1412 
1413 			    case 2:
1414 				addstr("You have come upon Robin Hood!\n");
1415 				Player.p_shield += Circle * 2.0;
1416 				Player.p_strength += Circle / 2.5 + 1.0;
1417 				break;
1418 
1419 			    case 3:
1420 				dtemp = ROLL(2.0 + Circle / 4.0, Circle / 1.2 + 10.0);
1421 				printw("You have found a +%.0f axe!\n", dtemp);
1422 				if (dtemp >= Player.p_sword)
1423 				    Player.p_sword = dtemp;
1424 				else
1425 				    SOMEBETTER();
1426 				break;
1427 			    }
1428 			break;
1429 		    /* end treasure type 6 */
1430 
1431 		    case 7:	/* treasure type 7 */
1432 			switch (whichtreasure)
1433 			    {
1434 			    case 1:
1435 				addstr("You've discovered a charm!\n");
1436 				++Player.p_charms;
1437 				break;
1438 
1439 			    case 2:
1440 				addstr("You have encountered Merlyn!\n");
1441 				Player.p_brains += Circle + 5.0;
1442 				Player.p_magiclvl += Circle / 3.0 + 5.0;
1443 				Player.p_mana += Circle * 10.0;
1444 				break;
1445 
1446 			    case 3:
1447 				dtemp = ROLL(5.0 + Circle / 3.0, Circle / 1.5 + 20.0);
1448 				printw("You have found a +%.0f war hammer!\n", dtemp);
1449 				if (dtemp >= Player.p_sword)
1450 				    Player.p_sword = dtemp;
1451 				else
1452 				    SOMEBETTER();
1453 				break;
1454 			    }
1455 			break;
1456 		    /* end treasure type 7 */
1457 
1458 		    case 8:	/* treasure type 8 */
1459 			switch (whichtreasure)
1460 			    {
1461 			    case 1:
1462 				addstr("You have found a healing potion.\n");
1463 				Player.p_poison = MIN(-2.0, Player.p_poison - 2.0);
1464 				break;
1465 
1466 			    case 2:
1467 				addstr("You have discovered a transporter.  Do you wish to go anywhere ? ");
1468 				ch = getanswer("NY", FALSE);
1469 				addstr("\n\n");
1470 				if (ch == 'Y')
1471 				    {
1472 				    double x, y;
1473 
1474 				    addstr("X Y Coordinates ? ");
1475 				    getstring(Databuf, SZ_DATABUF);
1476 				    sscanf(Databuf, "%lf %lf", &x, &y);
1477 				    altercoordinates(x, y, A_FORCED);
1478 				    }
1479 				break;
1480 
1481 			    case 3:
1482 				dtemp = ROLL(10.0 + Circle / 1.2, Circle * 3.0 + 30.0);
1483 				printw("You've found a +%.0f sword!\n", dtemp);
1484 				if (dtemp >= Player.p_sword)
1485 				    Player.p_sword = dtemp;
1486 				else
1487 				    SOMEBETTER();
1488 				break;
1489 			    }
1490 			break;
1491 		    /* end treasure type 8 */
1492 
1493 		    case 10:
1494 		    case 11:
1495 		    case 12:
1496 		    case 13:	/* treasure types 10 - 13 */
1497 			if (drandom() < 0.33)
1498 			    {
1499 			    if (Curmonster.m_treasuretype == 10)
1500 				{
1501 				addstr("You've found a pair of elven boots!\n");
1502 				Player.p_quickness += 2.0;
1503 				break;
1504 				}
1505 			    else if (Curmonster.m_treasuretype == 11
1506 				&& !Player.p_palantir)
1507 				{
1508 				addstr("You've acquired Saruman's palantir.\n");
1509 				Player.p_palantir = TRUE;
1510 				break;
1511 				}
1512 			    else if (Player.p_ring.ring_type == R_NONE
1513 				&& Player.p_specialtype < SC_COUNCIL
1514 				&& (Curmonster.m_treasuretype == 12
1515 				|| Curmonster.m_treasuretype == 13))
1516 				/* roll up a ring */
1517 				{
1518 				if (drandom() < 0.8)
1519 				    /* regular rings */
1520 				    {
1521 				    if (Curmonster.m_treasuretype == 12)
1522 					{
1523 					whichtreasure = R_NAZREG;
1524 					temp = 35;
1525 					}
1526 				    else
1527 					{
1528 					whichtreasure = R_DLREG;
1529 					temp = 0;
1530 					}
1531 				    }
1532 				else
1533 				    /* bad rings */
1534 				    {
1535 				    whichtreasure = R_BAD;
1536 				    temp = 15 + Statptr->c_ringduration + (int) ROLL(0,5);
1537 				    }
1538 
1539 				addstr("You've discovered a ring.  Will you pick it up ? ");
1540 				ch = getanswer("NY", FALSE);
1541 				addstr("\n\n");
1542 
1543 				if (ch == 'Y')
1544 				    {
1545 				    Player.p_ring.ring_type = whichtreasure;
1546 				    Player.p_ring.ring_duration = temp;
1547 				    }
1548 
1549 				break;
1550 				}
1551 			    }
1552 			/* end treasure types 10 - 13 */
1553 			/* fall through to treasure type 9 if no treasure from above */
1554 
1555 			case 9:	/* treasure type 9 */
1556 			    switch (whichtreasure)
1557 				{
1558 				case 1:
1559 				    if (Player.p_level <= 1000.0
1560 					&& Player.p_crowns <= 3
1561 					&& Player.p_level >= 10.0)
1562 					{
1563 					addstr("You have found a golden crown!\n");
1564 					++Player.p_crowns;
1565 					break;
1566 					}
1567 				    /* fall through otherwise */
1568 
1569 				case 2:
1570 				    addstr("You've been blessed!\n");
1571 				    Player.p_blessing = TRUE;
1572 				    Player.p_sin /= 3.0;
1573 				    Player.p_energy = Player.p_maxenergy + Player.p_shield;
1574 				    Player.p_mana += 100.0 * Circle;
1575 				    break;
1576 
1577 				case 3:
1578 				    dtemp = ROLL(1.0, Circle / 5.0 + 5.0);
1579 				    dtemp = MIN(dtemp, 99.0);
1580 				    printw("You have discovered some +%.0f quicksilver!\n",dtemp);
1581 				    if (dtemp >= Player.p_quksilver)
1582 					Player.p_quksilver = dtemp;
1583 				    else
1584 					SOMEBETTER();
1585 				    break;
1586 				}
1587 			    break;
1588 		    /* end treasure type 9 */
1589 		    }
1590 	}
1591 }
1592 /**/
1593 /************************************************************************
1594 /
1595 / FUNCTION NAME: cursedtreasure()
1596 /
1597 / FUNCTION: take care of cursed treasure
1598 /
1599 / AUTHOR: E. A. Estes, 12/4/85
1600 /
1601 / ARGUMENTS: none
1602 /
1603 / RETURN VALUE: none
1604 /
1605 / MODULES CALLED: waddstr()
1606 /
1607 / GLOBAL INPUTS: Player, *stdscr
1608 /
1609 / GLOBAL OUTPUTS: Player
1610 /
1611 / DESCRIPTION:
1612 /	Handle cursed treasure.  Look for amulets and charms to save
1613 /	the player from the curse.
1614 /
1615 *************************************************************************/
1616 
1617 cursedtreasure()
1618 {
1619     if (Player.p_charms > 0)
1620 	{
1621 	addstr("But your charm saved you!\n");
1622 	--Player.p_charms;
1623 	}
1624     else if (Player.p_amulets > 0)
1625 	{
1626 	addstr("But your amulet saved you!\n");
1627 	--Player.p_amulets;
1628 	}
1629     else
1630 	{
1631 	Player.p_energy = (Player.p_maxenergy + Player.p_shield) / 10.0;
1632 	Player.p_poison += 0.25;
1633 	}
1634 }
1635 /**/
1636 /************************************************************************
1637 /
1638 / FUNCTION NAME: scramblestats()
1639 /
1640 / FUNCTION: scramble some selected statistics
1641 /
1642 / AUTHOR: E. A. Estes, 12/4/85
1643 /
1644 / ARGUMENTS: none
1645 /
1646 / RETURN VALUE: none
1647 /
1648 / MODULES CALLED: floor(), drandom()
1649 /
1650 / GLOBAL INPUTS: Player
1651 /
1652 / GLOBAL OUTPUTS: Player
1653 /
1654 / DESCRIPTION:
1655 /	Swap a few player statistics randomly.
1656 /
1657 *************************************************************************/
1658 
1659 scramblestats()
1660 {
1661 double	dbuf[6];		/* to put statistic in */
1662 double	dtemp1, dtemp2;		/* for swapping values */
1663 int	first, second;	/* indices for swapping */
1664 double  *dptr;		/* pointer for filling and emptying buf[] */
1665 
1666     /* fill buffer */
1667     dptr = &dbuf[0];
1668     *dptr++ = Player.p_strength;
1669     *dptr++ = Player.p_mana;
1670     *dptr++ = Player.p_brains;
1671     *dptr++ = Player.p_magiclvl;
1672     *dptr++ = Player.p_energy;
1673     *dptr = Player.p_sin;
1674 
1675     /* pick values to swap */
1676     first = (int) ROLL(0, 5);
1677     second = (int) ROLL(0, 5);
1678 
1679     /* swap values */
1680     dptr = &dbuf[0];
1681     dtemp1 = dptr[first];
1682     /* this expression is split to prevent a compiler loop on some compilers */
1683     dtemp2 = dptr[second];
1684     dptr[first] = dtemp2;
1685     dptr[second] = dtemp1;
1686 
1687     /* empty buffer */
1688     Player.p_strength = *dptr++;
1689     Player.p_mana = *dptr++;
1690     Player.p_brains = *dptr++;
1691     Player.p_magiclvl = *dptr++;
1692     Player.p_energy = *dptr++;
1693     Player.p_sin = *dptr;
1694 }
1695