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