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