]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - phantasia/fight.c
WARNSify, KNFify (inc. removing extremely verbose & useless comments), ...
[bsdgames-darwin.git] / phantasia / fight.c
1 /* $NetBSD: fight.c,v 1.3 1997/10/13 02:18:12 lukem Exp $ */
2
3 /*
4 * fight.c Phantasia monster fighting routines
5 */
6
7 #include "include.h"
8
9 void
10 encounter(particular)
11 int particular;
12 {
13 bool firsthit = Player.p_blessing; /* set if player gets the
14 * first hit */
15 int flockcnt = 1; /* how many time flocked */
16
17 /* let others know what we are doing */
18 Player.p_status = S_MONSTER;
19 writerecord(&Player, Fileloc);
20
21 #if __GNUC__
22 (void)&firsthit; /* XXX shut up gcc */
23 #endif
24
25 #ifdef SYS5
26 flushinp();
27 #endif
28
29 Shield = 0.0; /* no shield up yet */
30
31 if (particular >= 0)
32 /* monster is specified */
33 Whichmonster = particular;
34 else
35 /* pick random monster */
36 Whichmonster = pickmonster();
37
38 setjmp(Fightenv); /* this is to enable changing fight state */
39
40 move(6, 0);
41 clrtobot(); /* clear bottom area of screen */
42
43 Lines = 9;
44 callmonster(Whichmonster); /* set up monster to fight */
45
46 Luckout = FALSE; /* haven't tried to luckout yet */
47
48 if (Curmonster.m_type == SM_MORGOTH)
49 mvprintw(4, 0, "You've encountered %s, Bane of the Council and Valar.\n",
50 Enemyname);
51
52 if (Curmonster.m_type == SM_UNICORN) {
53 if (Player.p_virgin) {
54 printw("You just subdued %s, thanks to the virgin.\n", Enemyname);
55 Player.p_virgin = FALSE;
56 } else {
57 printw("You just saw %s running away!\n", Enemyname);
58 Curmonster.m_experience = 0.0;
59 Curmonster.m_treasuretype = 0;
60 }
61 } else
62 /* not a special monster */
63 for (;;)
64 /* print header, and arbitrate between player and
65 * monster */
66 {
67 mvprintw(6, 0, "You are being attacked by %s, EXP: %.0f (Size: %.0f)\n",
68 Enemyname, Curmonster.m_experience, Circle);
69
70 displaystats();
71 mvprintw(1, 26, "%20.0f", Player.p_energy + Shield); /* overprint energy */
72 readmessage();
73
74 if (Curmonster.m_type == SM_DARKLORD
75 && Player.p_blessing
76 && Player.p_charms > 0)
77 /* overpower Dark Lord with blessing and charm */
78 {
79 mvprintw(7, 0, "You just overpowered %s!", Enemyname);
80 Lines = 8;
81 Player.p_blessing = FALSE;
82 --Player.p_charms;
83 break;
84 }
85 /* allow paralyzed monster to wake up */
86 Curmonster.m_speed = MIN(Curmonster.m_speed + 1.0, Curmonster.m_maxspeed);
87
88 if (drandom() * Curmonster.m_speed > drandom() * Player.p_speed
89 /* monster is faster */
90 && Curmonster.m_type != SM_DARKLORD
91 /* not D. L. */
92 && Curmonster.m_type != SM_SHRIEKER
93 /* not mimic */
94 && !firsthit)
95 /* monster gets a hit */
96 monsthits();
97 else
98 /* player gets a hit */
99 {
100 firsthit = FALSE;
101 playerhits();
102 }
103
104 refresh();
105
106 if (Lines > LINES - 2)
107 /* near bottom of screen - pause */
108 {
109 more(Lines);
110 move(Lines = 8, 0);
111 clrtobot();
112 }
113 if (Player.p_energy <= 0.0)
114 /* player died */
115 {
116 more(Lines);
117 death(Enemyname);
118 cancelmonster();
119 break; /* fight ends if the player is saved
120 * from death */
121 }
122 if (Curmonster.m_energy <= 0.0)
123 /* monster died */
124 break;
125 }
126
127 /* give player credit for killing monster */
128 Player.p_experience += Curmonster.m_experience;
129
130 if (drandom() < Curmonster.m_flock / 100.0)
131 /* monster flocks */
132 {
133 more(Lines);
134 ++flockcnt;
135 longjmp(Fightenv, 0);
136 /* NOTREACHED */
137 } else
138 if (Circle > 1.0
139 && Curmonster.m_treasuretype > 0
140 && drandom() > 0.2 + pow(0.4, (double) (flockcnt / 3 + Circle / 3.0)))
141 /* monster has treasure; this takes # of flocks and
142 * size into account */
143 {
144 more(Lines);
145 awardtreasure();
146 }
147 /* pause before returning */
148 getyx(stdscr, Lines, flockcnt);
149 more(Lines + 1);
150
151 Player.p_ring.ring_inuse = FALSE; /* not using ring */
152
153 /* clean up the screen */
154 move(4, 0);
155 clrtobot();
156 }
157
158 int
159 pickmonster()
160 {
161 if (Player.p_specialtype == SC_VALAR)
162 /* even chance of any monster */
163 return ((int) ROLL(0.0, 100.0));
164
165 if (Marsh)
166 /* water monsters */
167 return ((int) ROLL(0.0, 15.0));
168
169 else
170 if (Circle > 24)
171 /* even chance of all non-water monsters */
172 return ((int) ROLL(14.0, 86.0));
173
174 else
175 if (Circle > 15)
176 /* chance of all non-water monsters, weighted
177 * toward middle */
178 return ((int) (ROLL(0.0, 50.0) + ROLL(14.0, 37.0)));
179
180 else
181 if (Circle > 8)
182 /* not all non-water monsters,
183 * weighted toward middle */
184 return ((int) (ROLL(0.0, 50.0) + ROLL(14.0, 26.0)));
185
186 else
187 if (Circle > 3)
188 /* even chance of some tamer
189 * non-water monsters */
190 return ((int) ROLL(14.0, 50.0));
191
192 else
193 /* even chance of some of the
194 * tamest non-water monsters */
195 return ((int) ROLL(14.0, 25.0));
196 }
197
198 void
199 playerhits()
200 {
201 double inflict; /* damage inflicted */
202 int ch; /* input */
203
204 mvaddstr(7, 0, "1:Melee 2:Skirmish 3:Evade 4:Spell 5:Nick ");
205
206 if (!Luckout)
207 /* haven't tried to luckout yet */
208 if (Curmonster.m_type == SM_MORGOTH)
209 /* cannot luckout against Morgoth */
210 addstr("6:Ally ");
211 else
212 addstr("6:Luckout ");
213
214 if (Player.p_ring.ring_type != R_NONE)
215 /* player has a ring */
216 addstr("7:Use Ring ");
217 else
218 clrtoeol();
219
220 ch = inputoption();
221
222 move(8, 0);
223 clrtobot(); /* clear any messages from before */
224 Lines = 9;
225 mvaddstr(4, 0, "\n\n"); /* clear status area */
226
227 switch (ch) {
228 case 'T': /* timeout; lose turn */
229 break;
230
231 case ' ':
232 case '1': /* melee */
233 /* melee affects monster's energy and strength */
234 inflict = ROLL(Player.p_might / 2.0 + 5.0, 1.3 * Player.p_might)
235 + (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
236
237 Curmonster.m_melee += inflict;
238 Curmonster.m_strength = Curmonster.m_o_strength
239 - Curmonster.m_melee / Curmonster.m_o_energy
240 * Curmonster.m_o_strength / 4.0;
241 hitmonster(inflict);
242 break;
243
244 case '2': /* skirmish */
245 /* skirmish affects monter's energy and speed */
246 inflict = ROLL(Player.p_might / 3.0 + 3.0, 1.1 * Player.p_might)
247 + (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
248
249 Curmonster.m_skirmish += inflict;
250 Curmonster.m_maxspeed = Curmonster.m_o_speed
251 - Curmonster.m_skirmish / Curmonster.m_o_energy
252 * Curmonster.m_o_speed / 4.0;
253 hitmonster(inflict);
254 break;
255
256 case '3': /* evade */
257 /* use brains and speed to try to evade */
258 if ((Curmonster.m_type == SM_DARKLORD
259 || Curmonster.m_type == SM_SHRIEKER
260 /* can always run from D. L. and shrieker */
261 || drandom() * Player.p_speed * Player.p_brains
262 > drandom() * Curmonster.m_speed * Curmonster.m_brains)
263 && (Curmonster.m_type != SM_MIMIC))
264 /* cannot run from mimic */
265 {
266 mvaddstr(Lines++, 0, "You got away!");
267 cancelmonster();
268 altercoordinates(0.0, 0.0, A_NEAR);
269 } else
270 mvprintw(Lines++, 0, "%s is still after you!", Enemyname);
271
272 break;
273
274 case 'M':
275 case '4': /* magic spell */
276 throwspell();
277 break;
278
279 case '5': /* nick */
280 /* hit 1 plus sword; give some experience */
281 inflict = 1.0 + Player.p_sword;
282 Player.p_experience += floor(Curmonster.m_experience / 10.0);
283 Curmonster.m_experience *= 0.92;
284 /* monster gets meaner */
285 Curmonster.m_maxspeed += 2.0;
286 Curmonster.m_speed = (Curmonster.m_speed < 0.0) ? 0.0 : Curmonster.m_speed + 2.0;
287 if (Curmonster.m_type == SM_DARKLORD)
288 /* Dark Lord; doesn't like to be nicked */
289 {
290 mvprintw(Lines++, 0,
291 "You hit %s %.0f times, and made him mad!", Enemyname, inflict);
292 Player.p_quickness /= 2.0;
293 altercoordinates(0.0, 0.0, A_FAR);
294 cancelmonster();
295 } else
296 hitmonster(inflict);
297 break;
298
299 case 'B':
300 case '6': /* luckout */
301 if (Luckout)
302 mvaddstr(Lines++, 0, "You already tried that.");
303 else {
304 Luckout = TRUE;
305 if (Curmonster.m_type == SM_MORGOTH)
306 /* Morgoth; ally */
307 {
308 if (drandom() < Player.p_sin / 100.0) {
309 mvprintw(Lines++, 0, "%s accepted!", Enemyname);
310 cancelmonster();
311 } else
312 mvaddstr(Lines++, 0, "Nope, he's not interested.");
313 } else
314 /* normal monster; use brains for success */
315 {
316 if ((drandom() + 0.333) * Player.p_brains
317 < (drandom() + 0.333) * Curmonster.m_brains)
318 mvprintw(Lines++, 0, "You blew it, %s.", Player.p_name);
319 else {
320 mvaddstr(Lines++, 0, "You made it!");
321 Curmonster.m_energy = 0.0;
322 }
323 }
324 }
325 break;
326
327 case '7': /* use ring */
328 if (Player.p_ring.ring_type != R_NONE) {
329 mvaddstr(Lines++, 0, "Now using ring.");
330 Player.p_ring.ring_inuse = TRUE;
331 if (Player.p_ring.ring_type != R_DLREG)
332 /* age ring */
333 --Player.p_ring.ring_duration;
334 }
335 break;
336 }
337
338 }
339
340 void
341 monsthits()
342 {
343 double inflict; /* damage inflicted */
344 int ch; /* input */
345
346 switch (Curmonster.m_type)
347 /* may be a special monster */
348 {
349 case SM_DARKLORD:
350 /* hits just enough to kill player */
351 inflict = (Player.p_energy + Shield) * 1.02;
352 goto SPECIALHIT;
353
354 case SM_SHRIEKER:
355 /* call a big monster */
356 mvaddstr(Lines++, 0,
357 "Shrieeeek!! You scared it, and it called one of its friends.");
358 more(Lines);
359 Whichmonster = (int) ROLL(70.0, 30.0);
360 longjmp(Fightenv, 0);
361 /* NOTREACHED */
362
363 case SM_BALROG:
364 /* take experience away */
365 inflict = ROLL(10.0, Curmonster.m_strength);
366 inflict = MIN(Player.p_experience, inflict);
367 mvprintw(Lines++, 0,
368 "%s took away %.0f experience points.", Enemyname, inflict);
369 Player.p_experience -= inflict;
370 return;
371
372 case SM_FAERIES:
373 if (Player.p_holywater > 0)
374 /* holy water kills when monster tries to hit */
375 {
376 mvprintw(Lines++, 0, "Your holy water killed it!");
377 --Player.p_holywater;
378 Curmonster.m_energy = 0.0;
379 return;
380 }
381 break;
382
383 case SM_NONE:
384 /* normal hit */
385 break;
386
387 default:
388 if (drandom() > 0.2)
389 /* normal hit */
390 break;
391
392 /* else special things */
393 switch (Curmonster.m_type) {
394 case SM_LEANAN:
395 /* takes some of the player's strength */
396 inflict = ROLL(1.0, (Circle - 1.0) / 2.0);
397 inflict = MIN(Player.p_strength, inflict);
398 mvprintw(Lines++, 0, "%s sapped %0.f of your strength!",
399 Enemyname, inflict);
400 Player.p_strength -= inflict;
401 Player.p_might -= inflict;
402 break;
403
404 case SM_SARUMAN:
405 if (Player.p_palantir)
406 /* take away palantir */
407 {
408 mvprintw(Lines++, 0, "Wormtongue stole your palantir!");
409 Player.p_palantir = FALSE;
410 } else
411 if (drandom() > 0.5)
412 /* gems turn to gold */
413 {
414 mvprintw(Lines++, 0,
415 "%s transformed your gems into gold!", Enemyname);
416 Player.p_gold += Player.p_gems;
417 Player.p_gems = 0.0;
418 } else
419 /* scramble some stats */
420 {
421 mvprintw(Lines++, 0, "%s scrambled your stats!", Enemyname);
422 scramblestats();
423 }
424 break;
425
426 case SM_THAUMATURG:
427 /* transport player */
428 mvprintw(Lines++, 0, "%s transported you!", Enemyname);
429 altercoordinates(0.0, 0.0, A_FAR);
430 cancelmonster();
431 break;
432
433 case SM_VORTEX:
434 /* suck up some mana */
435 inflict = ROLL(0, 7.5 * Circle);
436 inflict = MIN(Player.p_mana, floor(inflict));
437 mvprintw(Lines++, 0,
438 "%s sucked up %.0f of your mana!", Enemyname, inflict);
439 Player.p_mana -= inflict;
440 break;
441
442 case SM_NAZGUL:
443 /* try to take ring if player has one */
444 if (Player.p_ring.ring_type != R_NONE)
445 /* player has a ring */
446 {
447 mvaddstr(Lines++, 0, "Will you relinguish your ring ? ");
448 ch = getanswer("YN", FALSE);
449 if (ch == 'Y')
450 /* take ring away */
451 {
452 Player.p_ring.ring_type = R_NONE;
453 Player.p_ring.ring_inuse = FALSE;
454 cancelmonster();
455 break;
456 }
457 }
458 /* otherwise, take some brains */
459 mvprintw(Lines++, 0,
460 "%s neutralized 1/5 of your brain!", Enemyname);
461 Player.p_brains *= 0.8;
462 break;
463
464 case SM_TIAMAT:
465 /* take some gold and gems */
466 mvprintw(Lines++, 0,
467 "%s took half your gold and gems and flew off.", Enemyname);
468 Player.p_gold /= 2.0;
469 Player.p_gems /= 2.0;
470 cancelmonster();
471 break;
472
473 case SM_KOBOLD:
474 /* steal a gold piece and run */
475 mvprintw(Lines++, 0,
476 "%s stole one gold piece and ran away.", Enemyname);
477 Player.p_gold = MAX(0.0, Player.p_gold - 1.0);
478 cancelmonster();
479 break;
480
481 case SM_SHELOB:
482 /* bite and (medium) poison */
483 mvprintw(Lines++, 0,
484 "%s has bitten and poisoned you!", Enemyname);
485 Player.p_poison -= 1.0;
486 break;
487
488 case SM_LAMPREY:
489 /* bite and (small) poison */
490 mvprintw(Lines++, 0, "%s bit and poisoned you!", Enemyname);
491 Player.p_poison += 0.25;
492 break;
493
494 case SM_BONNACON:
495 /* fart and run */
496 mvprintw(Lines++, 0, "%s farted and scampered off.", Enemyname);
497 Player.p_energy /= 2.0; /* damage from fumes */
498 cancelmonster();
499 break;
500
501 case SM_SMEAGOL:
502 if (Player.p_ring.ring_type != R_NONE)
503 /* try to steal ring */
504 {
505 mvprintw(Lines++, 0,
506 "%s tried to steal your ring, ", Enemyname);
507 if (drandom() > 0.1)
508 addstr("but was unsuccessful.");
509 else {
510 addstr("and ran away with it!");
511 Player.p_ring.ring_type = R_NONE;
512 cancelmonster();
513 }
514 }
515 break;
516
517 case SM_SUCCUBUS:
518 /* inflict damage through shield */
519 inflict = ROLL(15.0, Circle * 10.0);
520 inflict = MIN(inflict, Player.p_energy);
521 mvprintw(Lines++, 0, "%s sapped %.0f of your energy.",
522 Enemyname, inflict);
523 Player.p_energy -= inflict;
524 break;
525
526 case SM_CERBERUS:
527 /* take all metal treasures */
528 mvprintw(Lines++, 0,
529 "%s took all your metal treasures!", Enemyname);
530 Player.p_crowns = 0;
531 Player.p_sword =
532 Player.p_shield =
533 Player.p_gold = 0.0;
534 cancelmonster();
535 break;
536
537 case SM_UNGOLIANT:
538 /* (large) poison and take a quickness */
539 mvprintw(Lines++, 0,
540 "%s poisoned you, and took one quik.", Enemyname);
541 Player.p_poison += 5.0;
542 Player.p_quickness -= 1.0;
543 break;
544
545 case SM_JABBERWOCK:
546 /* fly away, and leave either a Jubjub bird or
547 * Bonnacon */
548 mvprintw(Lines++, 0,
549 "%s flew away, and left you to contend with one of its friends.",
550 Enemyname);
551 Whichmonster = 55 + (drandom() > 0.5) ? 22 : 0;
552 longjmp(Fightenv, 0);
553 /* NOTREACHED */
554
555 case SM_TROLL:
556 /* partially regenerate monster */
557 mvprintw(Lines++, 0,
558 "%s partially regenerated his energy.!", Enemyname);
559 Curmonster.m_energy +=
560 floor((Curmonster.m_o_energy - Curmonster.m_energy) / 2.0);
561 Curmonster.m_strength = Curmonster.m_o_strength;
562 Curmonster.m_melee = Curmonster.m_skirmish = 0.0;
563 Curmonster.m_maxspeed = Curmonster.m_o_speed;
564 break;
565
566 case SM_WRAITH:
567 if (!Player.p_blindness)
568 /* make blind */
569 {
570 mvprintw(Lines++, 0, "%s blinded you!", Enemyname);
571 Player.p_blindness = TRUE;
572 Enemyname = "A monster";
573 }
574 break;
575 }
576 return;
577 }
578
579 /* fall through to here if monster inflicts a normal hit */
580 inflict = drandom() * Curmonster.m_strength + 0.5;
581 SPECIALHIT:
582 mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, inflict);
583
584 if ((Shield -= inflict) < 0) {
585 Player.p_energy += Shield;
586 Shield = 0.0;
587 }
588 }
589
590 void
591 cancelmonster()
592 {
593 Curmonster.m_energy = 0.0;
594 Curmonster.m_experience = 0.0;
595 Curmonster.m_treasuretype = 0;
596 Curmonster.m_flock = 0.0;
597 }
598
599 void
600 hitmonster(inflict)
601 double inflict;
602 {
603 mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, inflict);
604 Curmonster.m_energy -= inflict;
605 if (Curmonster.m_energy > 0.0) {
606 if (Curmonster.m_type == SM_DARKLORD || Curmonster.m_type == SM_SHRIEKER)
607 /* special monster didn't die */
608 monsthits();
609 } else
610 /* monster died. print message. */
611 {
612 if (Curmonster.m_type == SM_MORGOTH)
613 mvaddstr(Lines++, 0, "You have defeated Morgoth, but he may return. . .");
614 else
615 /* all other types of monsters */
616 {
617 mvprintw(Lines++, 0, "You killed it. Good work, %s.", Player.p_name);
618
619 if (Curmonster.m_type == SM_MIMIC
620 && strcmp(Curmonster.m_name, "A Mimic") != 0
621 && !Player.p_blindness)
622 mvaddstr(Lines++, 0, "The body slowly changes into the form of a mimic.");
623 }
624 }
625 }
626
627 void
628 throwspell()
629 {
630 double inflict; /* damage inflicted */
631 double dtemp; /* for dtemporary calculations */
632 int ch; /* input */
633
634 inflict = 0;
635 mvaddstr(7, 0, "\n\n"); /* clear menu area */
636
637 if (Player.p_magiclvl >= ML_ALLORNOTHING)
638 mvaddstr(7, 0, "1:All or Nothing ");
639 if (Player.p_magiclvl >= ML_MAGICBOLT)
640 addstr("2:Magic Bolt ");
641 if (Player.p_magiclvl >= ML_FORCEFIELD)
642 addstr("3:Force Field ");
643 if (Player.p_magiclvl >= ML_XFORM)
644 addstr("4:Transform ");
645 if (Player.p_magiclvl >= ML_INCRMIGHT)
646 addstr("5:Increase Might\n");
647 if (Player.p_magiclvl >= ML_INVISIBLE)
648 mvaddstr(8, 0, "6:Invisibility ");
649 if (Player.p_magiclvl >= ML_XPORT)
650 addstr("7:Transport ");
651 if (Player.p_magiclvl >= ML_PARALYZE)
652 addstr("8:Paralyze ");
653 if (Player.p_specialtype >= SC_COUNCIL)
654 addstr("9:Specify");
655 mvaddstr(4, 0, "Spell ? ");
656
657 ch = getanswer(" ", TRUE);
658
659 mvaddstr(7, 0, "\n\n"); /* clear menu area */
660
661 if (Curmonster.m_type == SM_MORGOTH && ch != '3')
662 /* can only throw force field against Morgoth */
663 ILLSPELL();
664 else
665 switch (ch) {
666 case '1': /* all or nothing */
667 if (drandom() < 0.25)
668 /* success */
669 {
670 inflict = Curmonster.m_energy * 1.01 + 1.0;
671
672 if (Curmonster.m_type == SM_DARKLORD)
673 /* all or nothing doesn't quite work
674 * against D. L. */
675 inflict *= 0.9;
676 } else
677 /* failure -- monster gets stronger and
678 * quicker */
679 {
680 Curmonster.m_o_strength = Curmonster.m_strength *= 2.0;
681 Curmonster.m_maxspeed *= 2.0;
682 Curmonster.m_o_speed *= 2.0;
683
684 /* paralyzed monsters wake up a bit */
685 Curmonster.m_speed = MAX(1.0, Curmonster.m_speed * 2.0);
686 }
687
688 if (Player.p_mana >= MM_ALLORNOTHING)
689 /* take a mana if player has one */
690 Player.p_mana -= MM_ALLORNOTHING;
691
692 hitmonster(inflict);
693 break;
694
695 case '2': /* magic bolt */
696 if (Player.p_magiclvl < ML_MAGICBOLT)
697 ILLSPELL();
698 else {
699 do
700 /* prompt for amount to expend */
701 {
702 mvaddstr(4, 0, "How much mana for bolt? ");
703 dtemp = floor(infloat());
704 }
705 while (dtemp < 0.0 || dtemp > Player.p_mana);
706
707 Player.p_mana -= dtemp;
708
709 if (Curmonster.m_type == SM_DARKLORD)
710 /* magic bolts don't work against D.
711 * L. */
712 inflict = 0.0;
713 else
714 inflict = dtemp * ROLL(15.0, sqrt(Player.p_magiclvl / 3.0 + 1.0));
715 mvaddstr(5, 0, "Magic Bolt fired!\n");
716 hitmonster(inflict);
717 }
718 break;
719
720 case '3': /* force field */
721 if (Player.p_magiclvl < ML_FORCEFIELD)
722 ILLSPELL();
723 else
724 if (Player.p_mana < MM_FORCEFIELD)
725 NOMANA();
726 else {
727 Player.p_mana -= MM_FORCEFIELD;
728 Shield = (Player.p_maxenergy + Player.p_shield) * 4.2 + 45.0;
729 mvaddstr(5, 0, "Force Field up.\n");
730 }
731 break;
732
733 case '4': /* transform */
734 if (Player.p_magiclvl < ML_XFORM)
735 ILLSPELL();
736 else
737 if (Player.p_mana < MM_XFORM)
738 NOMANA();
739 else {
740 Player.p_mana -= MM_XFORM;
741 Whichmonster = (int) ROLL(0.0, 100.0);
742 longjmp(Fightenv, 0);
743 /* NOTREACHED */
744 }
745 break;
746
747 case '5': /* increase might */
748 if (Player.p_magiclvl < ML_INCRMIGHT)
749 ILLSPELL();
750 else
751 if (Player.p_mana < MM_INCRMIGHT)
752 NOMANA();
753 else {
754 Player.p_mana -= MM_INCRMIGHT;
755 Player.p_might +=
756 (1.2 * (Player.p_strength + Player.p_sword)
757 + 5.0 - Player.p_might) / 2.0;
758 mvprintw(5, 0, "New strength: %.0f\n", Player.p_might);
759 }
760 break;
761
762 case '6': /* invisible */
763 if (Player.p_magiclvl < ML_INVISIBLE)
764 ILLSPELL();
765 else
766 if (Player.p_mana < MM_INVISIBLE)
767 NOMANA();
768 else {
769 Player.p_mana -= MM_INVISIBLE;
770 Player.p_speed +=
771 (1.2 * (Player.p_quickness + Player.p_quksilver)
772 + 5.0 - Player.p_speed) / 2.0;
773 mvprintw(5, 0, "New quickness: %.0f\n", Player.p_speed);
774 }
775 break;
776
777 case '7': /* transport */
778 if (Player.p_magiclvl < ML_XPORT)
779 ILLSPELL();
780 else
781 if (Player.p_mana < MM_XPORT)
782 NOMANA();
783 else {
784 Player.p_mana -= MM_XPORT;
785 if (Player.p_brains + Player.p_magiclvl
786 < Curmonster.m_experience / 200.0 * drandom()) {
787 mvaddstr(5, 0, "Transport backfired!\n");
788 altercoordinates(0.0, 0.0, A_FAR);
789 cancelmonster();
790 } else {
791 mvprintw(5, 0, "%s is transported.\n", Enemyname);
792 if (drandom() < 0.3)
793 /* monster didn't drop
794 * its treasure */
795 Curmonster.m_treasuretype = 0;
796
797 Curmonster.m_energy = 0.0;
798 }
799 }
800 break;
801
802 case '8': /* paralyze */
803 if (Player.p_magiclvl < ML_PARALYZE)
804 ILLSPELL();
805 else
806 if (Player.p_mana < MM_PARALYZE)
807 NOMANA();
808 else {
809 Player.p_mana -= MM_PARALYZE;
810 if (Player.p_magiclvl >
811 Curmonster.m_experience / 1000.0 * drandom()) {
812 mvprintw(5, 0, "%s is held.\n", Enemyname);
813 Curmonster.m_speed = -2.0;
814 } else
815 mvaddstr(5, 0, "Monster unaffected.\n");
816 }
817 break;
818
819 case '9': /* specify */
820 if (Player.p_specialtype < SC_COUNCIL)
821 ILLSPELL();
822 else
823 if (Player.p_mana < MM_SPECIFY)
824 NOMANA();
825 else {
826 Player.p_mana -= MM_SPECIFY;
827 mvaddstr(5, 0, "Which monster do you want [0-99] ? ");
828 Whichmonster = (int) infloat();
829 Whichmonster = MAX(0, MIN(99, Whichmonster));
830 longjmp(Fightenv, 0);
831 /* NOTREACHED */
832 }
833 break;
834 }
835 }
836
837 void
838 callmonster(which)
839 int which;
840 {
841 struct monster Othermonster; /* to find a name for mimics */
842
843 which = MIN(which, 99); /* make sure within range */
844
845 /* fill structure */
846 fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0);
847 fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
848
849 /* handle some special monsters */
850 if (Curmonster.m_type == SM_MODNAR) {
851 if (Player.p_specialtype < SC_COUNCIL)
852 /* randomize some stats */
853 {
854 Curmonster.m_strength *= drandom() + 0.5;
855 Curmonster.m_brains *= drandom() + 0.5;
856 Curmonster.m_speed *= drandom() + 0.5;
857 Curmonster.m_energy *= drandom() + 0.5;
858 Curmonster.m_experience *= drandom() + 0.5;
859 Curmonster.m_treasuretype =
860 (int) ROLL(0.0, (double) Curmonster.m_treasuretype);
861 } else
862 /* make Modnar into Morgoth */
863 {
864 strcpy(Curmonster.m_name, "Morgoth");
865 Curmonster.m_strength = drandom() * (Player.p_maxenergy + Player.p_shield) / 1.4
866 + drandom() * (Player.p_maxenergy + Player.p_shield) / 1.5;
867 Curmonster.m_brains = Player.p_brains;
868 Curmonster.m_energy = Player.p_might * 30.0;
869 Curmonster.m_type = SM_MORGOTH;
870 Curmonster.m_speed = Player.p_speed * 1.1
871 + (Player.p_specialtype == SC_EXVALAR) ? Player.p_speed : 0.0;
872 Curmonster.m_flock = 0.0;
873 Curmonster.m_treasuretype = 0;
874 Curmonster.m_experience = 0.0;
875 }
876 } else
877 if (Curmonster.m_type == SM_MIMIC)
878 /* pick another name */
879 {
880 which = (int) ROLL(0.0, 100.0);
881 fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0);
882 fread(&Othermonster, SZ_MONSTERSTRUCT, 1, Monstfp);
883 strcpy(Curmonster.m_name, Othermonster.m_name);
884 }
885 truncstring(Curmonster.m_name);
886
887 if (Curmonster.m_type != SM_MORGOTH)
888 /* adjust stats based on which circle player is in */
889 {
890 Curmonster.m_strength *= (1.0 + Circle / 2.0);
891 Curmonster.m_brains *= Circle;
892 Curmonster.m_speed += Circle * 1.e-9;
893 Curmonster.m_energy *= Circle;
894 Curmonster.m_experience *= Circle;
895 }
896 if (Player.p_blindness)
897 /* cannot see monster if blind */
898 Enemyname = "A monster";
899 else
900 Enemyname = Curmonster.m_name;
901
902 if (Player.p_speed <= 0.0)
903 /* make Player.p_speed positive */
904 {
905 Curmonster.m_speed += -Player.p_speed;
906 Player.p_speed = 1.0;
907 }
908 /* fill up the rest of the structure */
909 Curmonster.m_o_strength = Curmonster.m_strength;
910 Curmonster.m_o_speed = Curmonster.m_maxspeed = Curmonster.m_speed;
911 Curmonster.m_o_energy = Curmonster.m_energy;
912 Curmonster.m_melee = Curmonster.m_skirmish = 0.0;
913 }
914
915 void
916 awardtreasure()
917 {
918 int whichtreasure; /* calculated treasure to grant */
919 int temp; /* temporary */
920 int ch; /* input */
921 double treasuretype; /* monster's treasure type */
922 double gold = 0.0; /* gold awarded */
923 double gems = 0.0; /* gems awarded */
924 double dtemp; /* for temporary calculations */
925
926 whichtreasure = (int) ROLL(1.0, 3.0); /* pick a treasure */
927 treasuretype = (double) Curmonster.m_treasuretype;
928
929 move(4, 0);
930 clrtobot();
931 move(6, 0);
932
933 if (drandom() > 0.65)
934 /* gold and gems */
935 {
936 if (Curmonster.m_treasuretype > 7)
937 /* gems */
938 {
939 gems = ROLL(1.0, (treasuretype - 7.0)
940 * (treasuretype - 7.0) * (Circle - 1.0) / 4.0);
941 printw("You have discovered %.0f gems!", gems);
942 } else
943 /* gold */
944 {
945 gold = ROLL(treasuretype * 10.0, treasuretype
946 * treasuretype * 10.0 * (Circle - 1.0));
947 printw("You have found %.0f gold pieces.", gold);
948 }
949
950 addstr(" Do you want to pick them up ? ");
951 ch = getanswer("NY", FALSE);
952 addstr("\n\n");
953
954 if (ch == 'Y')
955 if (drandom() < treasuretype / 35.0 + 0.04)
956 /* cursed */
957 {
958 addstr("They were cursed!\n");
959 cursedtreasure();
960 } else
961 collecttaxes(gold, gems);
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 }