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