2 * fight.c Phantasia monster fighting routines
4 * $FreeBSD: src/games/phantasia/fight.c,v 1.7 1999/11/16 02:57:33 billf Exp $
5 * $DragonFly: src/games/phantasia/fight.c,v 1.3 2005/05/31 00:06:26 swildner Exp $
11 /* functions which we need to know about */
13 extern int getanswer(const char *, bool);
14 extern void getstring(char *, int);
15 extern double infloat(void);
16 extern int inputoption(void);
17 extern void more(int);
19 extern void altercoordinates(double, double, int);
20 extern void collecttaxes(double, double);
21 extern void death(const char *);
22 extern void displaystats(void);
23 extern void readmessage(void);
24 extern void truncstring(char *);
25 extern void writerecord(struct player
*, long);
27 extern double drandom(void);
29 void awardtreasure(void);
30 void callmonster(int);
31 void cancelmonster(void);
32 void cursedtreasure(void);
34 void hitmonster(double);
35 int pickmonster(void);
37 void playerhits(void);
38 void scramblestats(void);
39 void throwspell(void);
42 * FUNCTION: monster battle routine
45 * int particular - particular monster to fight if >= 0
47 * GLOBAL INPUTS: Curmonster, Whichmonster, LINES, Lines, Circle, Shield,
48 * Player, *stdscr, Fileloc, Fightenv[], *Enemyname
50 * GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player, Luckout
53 * Choose a monster and check against some special types.
54 * Arbitrate between monster and player. Watch for either
59 encounter(int particular
)
61 volatile bool firsthit
= Player
.p_blessing
; /* set if player gets the first hit */
62 int flockcnt
= 1; /* how many time flocked */
64 /* let others know what we are doing */
65 Player
.p_status
= S_MONSTER
;
66 writerecord(&Player
, Fileloc
);
72 Shield
= 0.0; /* no shield up yet */
75 /* monster is specified */
76 Whichmonster
= particular
;
78 /* pick random monster */
79 Whichmonster
= pickmonster();
81 setjmp(Fightenv
); /* this is to enable changing fight state */
84 clrtobot(); /* clear bottom area of screen */
87 callmonster(Whichmonster
); /* set up monster to fight */
89 Luckout
= FALSE
; /* haven't tried to luckout yet */
91 if (Curmonster
.m_type
== SM_MORGOTH
)
92 mvprintw(4, 0, "You've encountered %s, Bane of the Council and Valar.\n",
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
;
100 printw("You just saw %s running away!\n", Enemyname
);
101 Curmonster
.m_experience
= 0.0;
102 Curmonster
.m_treasuretype
= 0;
105 /* not a special monster */
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
);
112 mvprintw(1, 26, "%20.0f", Player
.p_energy
+ Shield
); /* overprint energy */
115 if (Curmonster
.m_type
== SM_DARKLORD
117 && Player
.p_charms
> 0) {
118 /* overpower Dark Lord with blessing and charm */
119 mvprintw(7, 0, "You just overpowered %s!", Enemyname
);
121 Player
.p_blessing
= FALSE
;
126 /* allow paralyzed monster to wake up */
127 Curmonster
.m_speed
= MIN(Curmonster
.m_speed
+ 1.0, Curmonster
.m_maxspeed
);
129 if (drandom() * Curmonster
.m_speed
> drandom() * Player
.p_speed
130 /* monster is faster */
131 && Curmonster
.m_type
!= SM_DARKLORD
133 && Curmonster
.m_type
!= SM_SHRIEKER
136 /* monster gets a hit */
139 /* player gets a hit */
146 if (Lines
> LINES
- 2) {
147 /* near bottom of screen - pause */
153 if (Player
.p_energy
<= 0.0) {
158 break; /* fight ends if the player is saved from death */
161 if (Curmonster
.m_energy
<= 0.0)
166 /* give player credit for killing monster */
167 Player
.p_experience
+= Curmonster
.m_experience
;
169 if (drandom() < Curmonster
.m_flock
/ 100.0) {
173 longjmp(Fightenv
, 0);
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 */
183 /* pause before returning */
184 getyx(stdscr
, Lines
, flockcnt
);
187 Player
.p_ring
.ring_inuse
= FALSE
; /* not using ring */
189 /* clean up the screen */
195 * FUNCTION: choose a monster based upon where we are
197 * RETURN VALUE: monster number to call
199 * GLOBAL INPUTS: Marsh, Circle, Player
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.
213 if (Player
.p_specialtype
== SC_VALAR
)
214 /* even chance of any monster */
215 return ((int)ROLL(0.0, 100.0));
219 return ((int)ROLL(0.0, 15.0));
221 else if (Circle
> 24)
222 /* even chance of all non-water monsters */
223 return ((int)ROLL(14.0, 86.0));
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)));
230 /* not all non-water monsters, weighted toward middle */
231 return ((int)(ROLL(0.0, 50.0) + ROLL(14.0, 26.0)));
234 /* even chance of some tamer non-water monsters */
235 return ((int)ROLL(14.0, 50.0));
238 /* even chance of some of the tamest non-water monsters */
239 return ((int)ROLL(14.0, 25.0));
243 * FUNCTION: prompt player for action in monster battle, and process
245 * GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, Luckout, *Enemyname
247 * GLOBAL OUTPUTS: Curmonster, Lines, Player, Luckout
250 * Process all monster battle options.
256 double inflict
; /* damage inflicted */
259 mvaddstr(7, 0, "1:Melee 2:Skirmish 3:Evade 4:Spell 5:Nick ");
262 /* haven't tried to luckout yet */
263 if (Curmonster
.m_type
== SM_MORGOTH
)
264 /* cannot luckout against Morgoth */
267 addstr("6:Luckout ");
270 if (Player
.p_ring
.ring_type
!= R_NONE
)
271 /* player has a ring */
272 addstr("7:Use Ring ");
279 clrtobot(); /* clear any messages from before */
281 mvaddstr(4, 0, "\n\n"); /* clear status area */
284 case 'T': /* timeout; lose turn */
288 case '1': /* melee */
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);
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;
300 case '2': /* skirmish */
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);
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;
312 case '3': /* evade */
313 /* use brains and speed to try to evade */
314 if ((Curmonster
.m_type
== SM_DARKLORD
||
315 Curmonster
.m_type
== SM_SHRIEKER
316 /* can always run from D. L. and shrieker */
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!");
323 altercoordinates(0.0, 0.0, A_NEAR
);
325 mvprintw(Lines
++, 0, "%s is still after you!", Enemyname
);
330 case '4': /* magic spell */
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 */
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
);
354 case '6': /* luckout */
356 mvaddstr(Lines
++, 0, "You already tried that.");
359 if (Curmonster
.m_type
== SM_MORGOTH
) {
361 if (drandom() < Player
.p_sin
/ 100.0) {
362 mvprintw(Lines
++, 0, "%s accepted!", Enemyname
);
365 mvaddstr(Lines
++, 0, "Nope, he's not interested.");
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
);
372 mvaddstr(Lines
++, 0, "You made it!");
373 Curmonster
.m_energy
= 0.0;
379 case '7': /* use ring */
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
)
385 --Player
.p_ring
.ring_duration
;
392 * FUNCTION: process a monster hitting the player
394 * GLOBAL INPUTS: Curmonster, Lines, Circle, Shield, Player, *stdscr,
395 * Fightenv[], *Enemyname
397 * GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player,
401 * Handle all special monsters here. If the monster is not a special
402 * one, simply roll a hit against the player.
408 double inflict
; /* damage inflicted */
411 switch (Curmonster
.m_type
) {
412 /* may be a special monster */
414 /* hits just enough to kill player */
415 inflict
= (Player
.p_energy
+ Shield
) * 1.02;
419 /* call a big monster */
421 "Shrieeeek!! You scared it, and it called one of its friends.");
423 Whichmonster
= (int)ROLL(70.0, 30.0);
424 longjmp(Fightenv
, 0);
428 /* take experience away */
429 inflict
= ROLL(10.0, Curmonster
.m_strength
);
430 inflict
= MIN(Player
.p_experience
, inflict
);
432 "%s took away %.0f experience points.", Enemyname
, inflict
);
433 Player
.p_experience
-= inflict
;
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;
455 /* else special things */
456 switch (Curmonster
.m_type
) {
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!",
463 Player
.p_strength
-= inflict
;
464 Player
.p_might
-= inflict
;
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 */
475 "%s transformed your gems into gold!", Enemyname
);
476 Player
.p_gold
+= Player
.p_gems
;
479 /* scramble some stats */
480 mvprintw(Lines
++, 0, "%s scrambled your stats!", Enemyname
);
486 /* transport player */
487 mvprintw(Lines
++, 0, "%s transported you!", Enemyname
);
488 altercoordinates(0.0, 0.0, A_FAR
);
493 /* suck up some mana */
494 inflict
= ROLL(0, 7.5 * Circle
);
495 inflict
= MIN(Player
.p_mana
, floor(inflict
));
497 "%s sucked up %.0f of your mana!", Enemyname
, inflict
);
498 Player
.p_mana
-= inflict
;
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
);
509 Player
.p_ring
.ring_type
= R_NONE
;
510 Player
.p_ring
.ring_inuse
= FALSE
;
516 /* otherwise, take some brains */
518 "%s neutralized 1/5 of your brain!", Enemyname
);
519 Player
.p_brains
*= 0.8;
523 /* take some gold and gems */
525 "%s took half your gold and gems and flew off.", Enemyname
);
526 Player
.p_gold
/= 2.0;
527 Player
.p_gems
/= 2.0;
532 /* steal a gold piece and run */
534 "%s stole one gold piece and ran away.", Enemyname
);
535 Player
.p_gold
= MAX(0.0, Player
.p_gold
- 1.0);
540 /* bite and (medium) poison */
542 "%s has bitten and poisoned you!", Enemyname
);
543 Player
.p_poison
-= 1.0;
547 /* bite and (small) poison */
548 mvprintw(Lines
++, 0, "%s bit and poisoned you!", Enemyname
);
549 Player
.p_poison
+= 0.25;
554 mvprintw(Lines
++, 0, "%s farted and scampered off.", Enemyname
);
555 Player
.p_energy
/= 2.0; /* damage from fumes */
560 if (Player
.p_ring
.ring_type
!= R_NONE
) {
561 /* try to steal ring */
563 "%s tried to steal your ring, ", Enemyname
);
565 addstr("but was unsuccessful.");
567 addstr("and ran away with it!");
568 Player
.p_ring
.ring_type
= R_NONE
;
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.",
580 Player
.p_energy
-= inflict
;
584 /* take all metal treasures */
586 "%s took all your metal treasures!", Enemyname
);
595 /* (large) poison and take a quickness */
597 "%s poisoned you, and took one quik.", Enemyname
);
598 Player
.p_poison
+= 5.0;
599 Player
.p_quickness
-= 1.0;
603 /* fly away, and leave either a Jubjub bird or Bonnacon */
605 "%s flew away, and left you to contend with one of its friends.",
607 Whichmonster
= 55 + (drandom() > 0.5) ? 22 : 0;
608 longjmp(Fightenv
, 0);
612 /* partially regenerate monster */
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
;
623 if (!Player
.p_blindness
) {
625 mvprintw(Lines
++, 0, "%s blinded you!", Enemyname
);
626 Player
.p_blindness
= TRUE
;
627 Enemyname
= "A monster";
634 /* fall through to here if monster inflicts a normal hit */
635 inflict
= drandom() * Curmonster
.m_strength
+ 0.5;
637 mvprintw(Lines
++, 0, "%s hit you %.0f times!", Enemyname
, inflict
);
639 if ((Shield
-= inflict
) < 0) {
640 Player
.p_energy
+= Shield
;
646 * FUNCTION: mark current monster as no longer active
648 * GLOBAL OUTPUTS: Curmonster
651 * Clear current monster's energy, experience, treasure type, and
652 * flock. This is the same as having the monster run away.
658 Curmonster
.m_energy
= 0.0;
659 Curmonster
.m_experience
= 0.0;
660 Curmonster
.m_treasuretype
= 0;
661 Curmonster
.m_flock
= 0.0;
665 * FUNCTION: inflict damage upon current monster
668 * double inflict - damage to inflict upon monster
670 * GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, *Enemyname
672 * GLOBAL OUTPUTS: Curmonster, Lines
675 * Hit monster specified number of times. Handle when monster dies,
676 * and a few special monsters.
680 hitmonster(double inflict
)
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 */
689 /* monster died. print message. */
690 if (Curmonster
.m_type
== SM_MORGOTH
)
691 mvaddstr(Lines
++, 0, "You have defeated Morgoth, but he may return. . .");
693 /* all other types of monsters */
694 mvprintw(Lines
++, 0, "You killed it. Good work, %s.", Player
.p_name
);
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.");
705 * FUNCTION: throw a magic spell
707 * GLOBAL INPUTS: Curmonster, Whichmonster, Nomana[], Player, *stdscr,
708 * Fightenv[], Illspell[], *Enemyname
710 * GLOBAL OUTPUTS: Curmonster, Whichmonster, Shield, Player
713 * Prompt player and process magic spells.
719 double inflict
; /* damage inflicted */
720 double dtemp
; /* for dtemporary calculations */
724 mvaddstr(7, 0, "\n\n"); /* clear menu area */
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
)
744 mvaddstr(4, 0, "Spell ? ");
746 ch
= getanswer(" ", TRUE
);
748 mvaddstr(7, 0, "\n\n"); /* clear menu area */
750 if (Curmonster
.m_type
== SM_MORGOTH
&& ch
!= '3')
751 /* can only throw force field against Morgoth */
755 case '1': /* all or nothing */
756 if (drandom() < 0.25) {
758 inflict
= Curmonster
.m_energy
* 1.01 + 1.0;
760 if (Curmonster
.m_type
== SM_DARKLORD
)
761 /* all or nothing doesn't quite work against D. L. */
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;
769 /* paralyzed monsters wake up a bit */
770 Curmonster
.m_speed
= MAX(1.0, Curmonster
.m_speed
* 2.0);
773 if (Player
.p_mana
>= MM_ALLORNOTHING
)
774 /* take a mana if player has one */
775 Player
.p_mana
-= MM_ALLORNOTHING
;
780 case '2': /* magic bolt */
781 if (Player
.p_magiclvl
< ML_MAGICBOLT
)
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
);
790 Player
.p_mana
-= dtemp
;
792 if (Curmonster
.m_type
== SM_DARKLORD
)
793 /* magic bolts don't work against D. L. */
796 inflict
= dtemp
* ROLL(15.0, sqrt(Player
.p_magiclvl
/ 3.0 + 1.0));
797 mvaddstr(5, 0, "Magic Bolt fired!\n");
802 case '3': /* force field */
803 if (Player
.p_magiclvl
< ML_FORCEFIELD
)
805 else if (Player
.p_mana
< MM_FORCEFIELD
)
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");
814 case '4': /* transform */
815 if (Player
.p_magiclvl
< ML_XFORM
)
817 else if (Player
.p_mana
< MM_XFORM
)
820 Player
.p_mana
-= MM_XFORM
;
821 Whichmonster
= (int)ROLL(0.0, 100.0);
822 longjmp(Fightenv
, 0);
827 case '5': /* increase might */
828 if (Player
.p_magiclvl
< ML_INCRMIGHT
)
830 else if (Player
.p_mana
< MM_INCRMIGHT
)
833 Player
.p_mana
-= MM_INCRMIGHT
;
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
);
841 case '6': /* invisible */
842 if (Player
.p_magiclvl
< ML_INVISIBLE
)
844 else if (Player
.p_mana
< MM_INVISIBLE
)
847 Player
.p_mana
-= MM_INVISIBLE
;
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
);
855 case '7': /* transport */
856 if (Player
.p_magiclvl
< ML_XPORT
)
858 else if (Player
.p_mana
< MM_XPORT
)
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
);
868 mvprintw(5, 0, "%s is transported.\n", Enemyname
);
870 /* monster didn't drop its treasure */
871 Curmonster
.m_treasuretype
= 0;
873 Curmonster
.m_energy
= 0.0;
878 case '8': /* paralyze */
879 if (Player
.p_magiclvl
< ML_PARALYZE
)
881 else if (Player
.p_mana
< MM_PARALYZE
)
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;
890 mvaddstr(5, 0, "Monster unaffected.\n");
894 case '9': /* specify */
895 if (Player
.p_specialtype
< SC_COUNCIL
)
897 else if (Player
.p_mana
< MM_SPECIFY
)
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);
912 * FUNCTION: read monster from file, and fill structure
915 * int which - which monster to call
917 * GLOBAL INPUTS: Curmonster, Circle, Player, *Monstfp
919 * GLOBAL OUTPUTS: Curmonster, Player, *Enemyname
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.
929 callmonster(int which
)
931 struct monster Othermonster
; /* to find a name for mimics */
933 which
= MIN(which
, 99); /* make sure within range */
936 fseek(Monstfp
, (long)which
* (long)SZ_MONSTERSTRUCT
, SEEK_SET
);
937 fread((char *)&Curmonster
, SZ_MONSTERSTRUCT
, 1, Monstfp
);
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
);
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;
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
);
972 truncstring(Curmonster
.m_name
);
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
;
983 if (Player
.p_blindness
)
984 /* cannot see monster if blind */
985 Enemyname
= "A monster";
987 Enemyname
= Curmonster
.m_name
;
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;
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;
1003 * FUNCTION: select a treasure
1005 * GLOBAL INPUTS: Somebetter[], Curmonster, Whichmonster, Circle, Player,
1006 * *stdscr, Databuf[], *Statptr, Fightenv[]
1008 * GLOBAL OUTPUTS: Whichmonster, Shield, Player
1011 * Roll up a treasure based upon monster type and size, and
1012 * certain player statistics.
1013 * Handle cursed treasure.
1019 int whichtreasure
; /* calculated treasure to grant */
1020 int temp
; /* temporary */
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 */
1027 whichtreasure
= (int)ROLL(1.0, 3.0); /* pick a treasure */
1028 treasuretype
= (double)Curmonster
.m_treasuretype
;
1034 if (drandom() > 0.65) {
1036 if (Curmonster
.m_treasuretype
> 7) {
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
);
1043 gold
= ROLL(treasuretype
* 10.0, treasuretype
1044 * treasuretype
* 10.0 * (Circle
- 1.0));
1045 printw("You have found %.0f gold pieces.", gold
);
1048 addstr(" Do you want to pick them up ? ");
1049 ch
= getanswer("NY", FALSE
);
1053 if (drandom() < treasuretype
/ 35.0 + 0.04) {
1055 addstr("They were cursed!\n");
1058 collecttaxes(gold
, gems
);
1063 /* other treasures */
1064 addstr("You have found some treasure. Do you want to inspect it ? ");
1065 ch
= getanswer("NY", FALSE
);
1070 else if (drandom() < 0.08 && Curmonster
.m_treasuretype
!= 4) {
1071 addstr("It was cursed!\n");
1075 switch (Curmonster
.m_treasuretype
) {
1076 case 1: /* treasure type 1 */
1077 switch (whichtreasure
) {
1079 addstr("You've discovered a power booster!\n");
1080 Player
.p_mana
+= ROLL(Circle
* 4.0, Circle
* 30.0);
1084 addstr("You have encountered a druid.\n");
1085 Player
.p_experience
+=
1086 ROLL(0.0, 2000.0 + Circle
* 400.0);
1090 addstr("You have found a holy orb.\n");
1091 Player
.p_sin
= MAX(0.0, Player
.p_sin
- 0.25);
1095 /* end treasure type 1 */
1097 case 2: /* treasure type 2 */
1098 switch (whichtreasure
) {
1100 addstr("You have found an amulet.\n");
1105 addstr("You've found some holy water!\n");
1106 ++Player
.p_holywater
;
1110 addstr("You've met a hermit!\n");
1111 Player
.p_sin
*= 0.75;
1112 Player
.p_mana
+= 12.0 * Circle
;
1116 /* end treasure type 2 */
1118 case 3: /* treasure type 3 */
1119 switch (whichtreasure
) {
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
;
1130 addstr("You have rescued a virgin. Will you be honorable ? ");
1131 ch
= getanswer("NY", FALSE
);
1134 Player
.p_virgin
= TRUE
;
1136 Player
.p_experience
+= 2000.0 * Circle
;
1142 addstr("You've discovered some athelas!\n");
1147 /* end treasure type 3 */
1149 case 4: /* treasure type 4 */
1150 addstr("You've found a scroll. Will you read it ? ");
1151 ch
= getanswer("NY", FALSE
);
1155 switch ((int)ROLL(1, 6)) {
1157 addstr("It throws up a shield for you next monster.\n");
1158 getyx(stdscr
, whichtreasure
, ch
);
1159 more(whichtreasure
);
1161 (Player
.p_maxenergy
+ Player
.p_energy
) * 5.5 + Circle
* 50.0;
1162 Whichmonster
= pickmonster();
1163 longjmp(Fightenv
, 0);
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);
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);
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);
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);
1198 addstr("It was cursed!\n");
1203 /* end treasure type 4 */
1205 case 5: /* treasure type 5 */
1206 switch (whichtreasure
) {
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
;
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
;
1226 addstr("You've found a tablet.\n");
1227 Player
.p_brains
+= 4.5 * Circle
;
1231 /* end treasure type 5 */
1233 case 6: /* treasure type 6 */
1234 switch (whichtreasure
) {
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
;
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;
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
;
1259 /* end treasure type 6 */
1261 case 7: /* treasure type 7 */
1262 switch (whichtreasure
) {
1264 addstr("You've discovered a charm!\n");
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;
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
;
1285 /* end treasure type 7 */
1287 case 8: /* treasure type 8 */
1288 switch (whichtreasure
) {
1290 addstr("You have found a healing potion.\n");
1291 Player
.p_poison
= MIN(-2.0, Player
.p_poison
- 2.0);
1295 addstr("You have discovered a transporter. Do you wish to go anywhere ? ");
1296 ch
= getanswer("NY", FALSE
);
1301 addstr("X Y Coordinates ? ");
1302 getstring(Databuf
, SZ_DATABUF
);
1303 sscanf(Databuf
, "%lf %lf", &x
, &y
);
1304 altercoordinates(x
, y
, A_FORCED
);
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
;
1318 /* end treasure type 8 */
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;
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
;
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) {
1341 if (Curmonster
.m_treasuretype
== 12) {
1342 whichtreasure
= R_NAZREG
;
1345 whichtreasure
= R_DLREG
;
1350 whichtreasure
= R_BAD
;
1351 temp
= 15 + Statptr
->c_ringduration
+ (int)ROLL(0, 5);
1354 addstr("You've discovered a ring. Will you pick it up ? ");
1355 ch
= getanswer("NY", FALSE
);
1359 Player
.p_ring
.ring_type
= whichtreasure
;
1360 Player
.p_ring
.ring_duration
= temp
;
1366 /* end treasure types 10 - 13 */
1367 /* fall through to treasure type 9 if no treasure from above */
1369 case 9: /* treasure type 9 */
1370 switch (whichtreasure
) {
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");
1379 /* fall through otherwise */
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
;
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
;
1400 /* end treasure type 9 */
1406 * FUNCTION: take care of cursed treasure
1408 * GLOBAL INPUTS: Player, *stdscr
1410 * GLOBAL OUTPUTS: Player
1413 * Handle cursed treasure. Look for amulets and charms to save
1414 * the player from the curse.
1418 cursedtreasure(void)
1420 if (Player
.p_charms
> 0) {
1421 addstr("But your charm saved you!\n");
1423 } else if (Player
.p_amulets
> 0) {
1424 addstr("But your amulet saved you!\n");
1427 Player
.p_energy
= (Player
.p_maxenergy
+ Player
.p_shield
) / 10.0;
1428 Player
.p_poison
+= 0.25;
1433 * FUNCTION: scramble some selected statistics
1435 * GLOBAL INPUTS: Player
1437 * GLOBAL OUTPUTS: Player
1440 * Swap a few player statistics randomly.
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[] */
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
;
1460 /* pick values to swap */
1461 first
= (int)ROLL(0, 5);
1462 second
= (int)ROLL(0, 5);
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
;
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
;