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