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