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