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