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