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