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