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