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