Merge from vendor branch FILE:
[dragonfly.git] / games / phantasia / fight.c
CommitLineData
984263bc
MD
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 $
1de703da 5 * $DragonFly: src/games/phantasia/fight.c,v 1.2 2003/06/17 04:25:24 dillon Exp $
984263bc
MD
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
41encounter(particular)
42int particular;
43{
44bool firsthit = Player.p_blessing; /* set if player gets the first hit */
45int 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
218pickmonster()
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
274playerhits()
275{
276double inflict; /* damage inflicted */
277int 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
453monsthits()
454{
455double inflict; /* damage inflicted */
456int 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;
696SPECIALHIT:
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
730cancelmonster()
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
763hitmonster(inflict)
764double 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
818throwspell()
819{
820double inflict; /* damage inflicted */
821double dtemp; /* for dtemporary calculations */
822int 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
1058callmonster(which)
1059int which;
1060{
1061struct 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
1168awardtreasure()
1169{
1170int whichtreasure; /* calculated treasure to grant */
1171int temp; /* temporary */
1172int ch; /* input */
1173double treasuretype; /* monster's treasure type */
1174double gold = 0.0; /* gold awarded */
1175double gems = 0.0; /* gems awarded */
1176double 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
1617cursedtreasure()
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
1659scramblestats()
1660{
1661double dbuf[6]; /* to put statistic in */
1662double dtemp1, dtemp2; /* for swapping values */
1663int first, second; /* indices for swapping */
1664double *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}