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