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