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