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);
30 int pickmonster(void);
31 void playerhits(void);
33 void cancelmonster(void);
34 void hitmonster(double);
35 void throwspell(void);
36 void callmonster(int);
37 void awardtreasure(void);
38 void cursedtreasure(void);
39 void scramblestats(void);
41 /************************************************************************
43 / FUNCTION NAME: encounter()
45 / FUNCTION: monster battle routine
47 / AUTHOR: E. A. Estes, 2/20/86
50 / int particular - particular monster to fight if >= 0
54 / MODULES CALLED: monsthits(), playerhits(), readmessage(), callmonster(),
55 / writerecord(), pickmonster(), displaystats(), pow(), cancelmonster(),
56 / awardtreasure(), more(), death(), wmove(), setjmp(), drandom(), printw(),
57 / longjmp(), wrefresh(), mvprintw(), wclrtobot()
59 / GLOBAL INPUTS: Curmonster, Whichmonster, LINES, Lines, Circle, Shield,
60 / Player, *stdscr, Fileloc, Fightenv[], *Enemyname
62 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player, Luckout
65 / Choose a monster and check against some special types.
66 / Arbitrate between monster and player. Watch for either
69 *************************************************************************/
72 encounter(int particular
)
74 volatile bool firsthit
= Player
.p_blessing
; /* set if player gets the first hit */
75 int flockcnt
= 1; /* how many time flocked */
77 /* let others know what we are doing */
78 Player
.p_status
= S_MONSTER
;
79 writerecord(&Player
, Fileloc
);
85 Shield
= 0.0; /* no shield up yet */
88 /* monster is specified */
89 Whichmonster
= particular
;
91 /* pick random monster */
92 Whichmonster
= pickmonster();
94 setjmp(Fightenv
); /* this is to enable changing fight state */
97 clrtobot(); /* clear bottom area of screen */
100 callmonster(Whichmonster
); /* set up monster to fight */
102 Luckout
= FALSE
; /* haven't tried to luckout yet */
104 if (Curmonster
.m_type
== SM_MORGOTH
)
105 mvprintw(4, 0, "You've encountered %s, Bane of the Council and Valar.\n",
108 if (Curmonster
.m_type
== SM_UNICORN
)
112 printw("You just subdued %s, thanks to the virgin.\n", Enemyname
);
113 Player
.p_virgin
= FALSE
;
117 printw("You just saw %s running away!\n", Enemyname
);
118 Curmonster
.m_experience
= 0.0;
119 Curmonster
.m_treasuretype
= 0;
123 /* not a special monster */
125 /* print header, and arbitrate between player and monster */
127 mvprintw(6, 0, "You are being attacked by %s, EXP: %.0f (Size: %.0f)\n",
128 Enemyname
, Curmonster
.m_experience
, Circle
);
131 mvprintw(1, 26, "%20.0f", Player
.p_energy
+ Shield
); /* overprint energy */
134 if (Curmonster
.m_type
== SM_DARKLORD
136 && Player
.p_charms
> 0)
137 /* overpower Dark Lord with blessing and charm */
139 mvprintw(7, 0, "You just overpowered %s!", Enemyname
);
141 Player
.p_blessing
= FALSE
;
146 /* allow paralyzed monster to wake up */
147 Curmonster
.m_speed
= MIN(Curmonster
.m_speed
+ 1.0, Curmonster
.m_maxspeed
);
149 if (drandom() * Curmonster
.m_speed
> drandom() * Player
.p_speed
150 /* monster is faster */
151 && Curmonster
.m_type
!= SM_DARKLORD
153 && Curmonster
.m_type
!= SM_SHRIEKER
156 /* monster gets a hit */
159 /* player gets a hit */
167 if (Lines
> LINES
- 2)
168 /* near bottom of screen - pause */
175 if (Player
.p_energy
<= 0.0)
181 break; /* fight ends if the player is saved from death */
184 if (Curmonster
.m_energy
<= 0.0)
189 /* give player credit for killing monster */
190 Player
.p_experience
+= Curmonster
.m_experience
;
192 if (drandom() < Curmonster
.m_flock
/ 100.0)
197 longjmp(Fightenv
, 0);
200 else if (Circle
> 1.0
201 && Curmonster
.m_treasuretype
> 0
202 && drandom() > 0.2 + pow(0.4, (double) (flockcnt
/ 3 + Circle
/ 3.0)))
203 /* monster has treasure; this takes # of flocks and size into account */
209 /* pause before returning */
210 getyx(stdscr
, Lines
, flockcnt
);
213 Player
.p_ring
.ring_inuse
= FALSE
; /* not using ring */
215 /* clean up the screen */
220 /************************************************************************
222 / FUNCTION NAME: pickmonster()
224 / FUNCTION: choose a monster based upon where we are
226 / AUTHOR: E. A. Estes, 2/20/86
230 / RETURN VALUE: monster number to call
232 / MODULES CALLED: floor(), drandom()
234 / GLOBAL INPUTS: Marsh, Circle, Player
236 / GLOBAL OUTPUTS: none
239 / Certain monsters can be found in certain areas of the grid.
240 / We take care of rolling them here.
241 / Unfortunately, this routine assumes that the monster data
242 / base is arranged in a particular order. If the data base
243 / is altered (to add monsters, or make them tougher), this
244 / routine may also need to be changed.
246 *************************************************************************/
251 if (Player
.p_specialtype
== SC_VALAR
)
252 /* even chance of any monster */
253 return((int) ROLL(0.0, 100.0));
257 return((int) ROLL(0.0, 15.0));
259 else if (Circle
> 24)
260 /* even chance of all non-water monsters */
261 return((int) ROLL(14.0, 86.0));
263 else if (Circle
> 15)
264 /* chance of all non-water monsters, weighted toward middle */
265 return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 37.0)));
268 /* not all non-water monsters, weighted toward middle */
269 return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 26.0)));
272 /* even chance of some tamer non-water monsters */
273 return((int) ROLL(14.0, 50.0));
276 /* even chance of some of the tamest non-water monsters */
277 return((int) ROLL(14.0, 25.0));
280 /************************************************************************
282 / FUNCTION NAME: playerhits()
284 / FUNCTION: prompt player for action in monster battle, and process
286 / AUTHOR: E. A. Estes, 12/4/85
292 / MODULES CALLED: hitmonster(), throwspell(), inputoption(), cancelmonster(),
293 / floor(), wmove(), drandom(), altercoordinates(), waddstr(), mvprintw(),
294 / wclrtoeol(), wclrtobot()
296 / GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, Luckout, *Enemyname
298 / GLOBAL OUTPUTS: Curmonster, Lines, Player, Luckout
301 / Process all monster battle options.
303 *************************************************************************/
308 double inflict
; /* damage inflicted */
311 mvaddstr(7, 0, "1:Melee 2:Skirmish 3:Evade 4:Spell 5:Nick ");
314 /* haven't tried to luckout yet */
315 if (Curmonster
.m_type
== SM_MORGOTH
)
316 /* cannot luckout against Morgoth */
319 addstr("6:Luckout ");
322 if (Player
.p_ring
.ring_type
!= R_NONE
)
323 /* player has a ring */
324 addstr("7:Use Ring ");
331 clrtobot(); /* clear any messages from before */
333 mvaddstr(4, 0, "\n\n"); /* clear status area */
337 case 'T': /* timeout; lose turn */
341 case '1': /* melee */
342 /* melee affects monster's energy and strength */
343 inflict
= ROLL(Player
.p_might
/ 2.0 + 5.0, 1.3 * Player
.p_might
)
344 + (Player
.p_ring
.ring_inuse
? Player
.p_might
: 0.0);
346 Curmonster
.m_melee
+= inflict
;
347 Curmonster
.m_strength
= Curmonster
.m_o_strength
348 - Curmonster
.m_melee
/ Curmonster
.m_o_energy
349 * Curmonster
.m_o_strength
/ 4.0;
353 case '2': /* skirmish */
354 /* skirmish affects monter's energy and speed */
355 inflict
= ROLL(Player
.p_might
/ 3.0 + 3.0, 1.1 * Player
.p_might
)
356 + (Player
.p_ring
.ring_inuse
? Player
.p_might
: 0.0);
358 Curmonster
.m_skirmish
+= inflict
;
359 Curmonster
.m_maxspeed
= Curmonster
.m_o_speed
360 - Curmonster
.m_skirmish
/ Curmonster
.m_o_energy
361 * Curmonster
.m_o_speed
/ 4.0;
365 case '3': /* evade */
366 /* use brains and speed to try to evade */
367 if ((Curmonster
.m_type
== SM_DARKLORD
368 || Curmonster
.m_type
== SM_SHRIEKER
369 /* can always run from D. L. and shrieker */
370 || drandom() * Player
.p_speed
* Player
.p_brains
371 > drandom() * Curmonster
.m_speed
* Curmonster
.m_brains
)
372 && (Curmonster
.m_type
!= SM_MIMIC
))
373 /* cannot run from mimic */
375 mvaddstr(Lines
++, 0, "You got away!");
377 altercoordinates(0.0, 0.0, A_NEAR
);
380 mvprintw(Lines
++, 0, "%s is still after you!", Enemyname
);
385 case '4': /* magic spell */
390 /* hit 1 plus sword; give some experience */
391 inflict
= 1.0 + Player
.p_sword
;
392 Player
.p_experience
+= floor(Curmonster
.m_experience
/ 10.0);
393 Curmonster
.m_experience
*= 0.92;
394 /* monster gets meaner */
395 Curmonster
.m_maxspeed
+= 2.0;
396 Curmonster
.m_speed
= (Curmonster
.m_speed
< 0.0) ? 0.0 : Curmonster
.m_speed
+ 2.0;
397 if (Curmonster
.m_type
== SM_DARKLORD
)
398 /* Dark Lord; doesn't like to be nicked */
401 "You hit %s %.0f times, and made him mad!", Enemyname
, inflict
);
402 Player
.p_quickness
/= 2.0;
403 altercoordinates(0.0, 0.0, A_FAR
);
411 case '6': /* luckout */
413 mvaddstr(Lines
++, 0, "You already tried that.");
417 if (Curmonster
.m_type
== SM_MORGOTH
)
420 if (drandom() < Player
.p_sin
/ 100.0)
422 mvprintw(Lines
++, 0, "%s accepted!", Enemyname
);
426 mvaddstr(Lines
++, 0, "Nope, he's not interested.");
429 /* normal monster; use brains for success */
431 if ((drandom() + 0.333) * Player
.p_brains
432 < (drandom() + 0.333) * Curmonster
.m_brains
)
433 mvprintw(Lines
++, 0, "You blew it, %s.", Player
.p_name
);
436 mvaddstr(Lines
++, 0, "You made it!");
437 Curmonster
.m_energy
= 0.0;
443 case '7': /* use ring */
444 if (Player
.p_ring
.ring_type
!= R_NONE
)
446 mvaddstr(Lines
++, 0, "Now using ring.");
447 Player
.p_ring
.ring_inuse
= TRUE
;
448 if (Player
.p_ring
.ring_type
!= R_DLREG
)
450 --Player
.p_ring
.ring_duration
;
457 /************************************************************************
459 / FUNCTION NAME: monsthits()
461 / FUNCTION: process a monster hitting the player
463 / AUTHOR: E. A. Estes, 12/4/85
469 / MODULES CALLED: cancelmonster(), scramblestats(), more(), floor(), wmove(),
470 / drandom(), altercoordinates(), longjmp(), waddstr(), mvprintw(),
473 / GLOBAL INPUTS: Curmonster, Lines, Circle, Shield, Player, *stdscr,
474 / Fightenv[], *Enemyname
476 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player,
480 / Handle all special monsters here. If the monster is not a special
481 / one, simply roll a hit against the player.
483 *************************************************************************/
488 double inflict
; /* damage inflicted */
491 switch (Curmonster
.m_type
)
492 /* may be a special monster */
495 /* hits just enough to kill player */
496 inflict
= (Player
.p_energy
+ Shield
) * 1.02;
500 /* call a big monster */
502 "Shrieeeek!! You scared it, and it called one of its friends.");
504 Whichmonster
= (int) ROLL(70.0, 30.0);
505 longjmp(Fightenv
, 0);
509 /* take experience away */
510 inflict
= ROLL(10.0, Curmonster
.m_strength
);
511 inflict
= MIN(Player
.p_experience
, inflict
);
513 "%s took away %.0f experience points.", Enemyname
, inflict
);
514 Player
.p_experience
-= inflict
;
518 if (Player
.p_holywater
> 0)
519 /* holy water kills when monster tries to hit */
521 mvprintw(Lines
++, 0, "Your holy water killed it!");
522 --Player
.p_holywater
;
523 Curmonster
.m_energy
= 0.0;
537 /* else special things */
538 switch (Curmonster
.m_type
)
541 /* takes some of the player's strength */
542 inflict
= ROLL(1.0, (Circle
- 1.0) / 2.0);
543 inflict
= MIN(Player
.p_strength
, inflict
);
544 mvprintw(Lines
++, 0, "%s sapped %0.f of your strength!",
546 Player
.p_strength
-= inflict
;
547 Player
.p_might
-= inflict
;
551 if (Player
.p_palantir
)
552 /* take away palantir */
554 mvprintw(Lines
++, 0, "Wormtongue stole your palantir!");
555 Player
.p_palantir
= FALSE
;
557 else if (drandom() > 0.5)
558 /* gems turn to gold */
561 "%s transformed your gems into gold!", Enemyname
);
562 Player
.p_gold
+= Player
.p_gems
;
566 /* scramble some stats */
568 mvprintw(Lines
++, 0, "%s scrambled your stats!", Enemyname
);
574 /* transport player */
575 mvprintw(Lines
++, 0, "%s transported you!", Enemyname
);
576 altercoordinates(0.0, 0.0, A_FAR
);
581 /* suck up some mana */
582 inflict
= ROLL(0, 7.5 * Circle
);
583 inflict
= MIN(Player
.p_mana
, floor(inflict
));
585 "%s sucked up %.0f of your mana!", Enemyname
, inflict
);
586 Player
.p_mana
-= inflict
;
590 /* try to take ring if player has one */
591 if (Player
.p_ring
.ring_type
!= R_NONE
)
592 /* player has a ring */
594 mvaddstr(Lines
++, 0, "Will you relinguish your ring ? ");
595 ch
= getanswer("YN", FALSE
);
599 Player
.p_ring
.ring_type
= R_NONE
;
600 Player
.p_ring
.ring_inuse
= FALSE
;
606 /* otherwise, take some brains */
608 "%s neutralized 1/5 of your brain!", Enemyname
);
609 Player
.p_brains
*= 0.8;
613 /* take some gold and gems */
615 "%s took half your gold and gems and flew off.", Enemyname
);
616 Player
.p_gold
/= 2.0;
617 Player
.p_gems
/= 2.0;
622 /* steal a gold piece and run */
624 "%s stole one gold piece and ran away.", Enemyname
);
625 Player
.p_gold
= MAX(0.0, Player
.p_gold
- 1.0);
630 /* bite and (medium) poison */
632 "%s has bitten and poisoned you!", Enemyname
);
633 Player
.p_poison
-= 1.0;
637 /* bite and (small) poison */
638 mvprintw(Lines
++, 0, "%s bit and poisoned you!", Enemyname
);
639 Player
.p_poison
+= 0.25;
644 mvprintw(Lines
++, 0, "%s farted and scampered off.", Enemyname
);
645 Player
.p_energy
/= 2.0; /* damage from fumes */
650 if (Player
.p_ring
.ring_type
!= R_NONE
)
651 /* try to steal ring */
654 "%s tried to steal your ring, ", Enemyname
);
656 addstr("but was unsuccessful.");
659 addstr("and ran away with it!");
660 Player
.p_ring
.ring_type
= R_NONE
;
667 /* inflict damage through shield */
668 inflict
= ROLL(15.0, Circle
* 10.0);
669 inflict
= MIN(inflict
, Player
.p_energy
);
670 mvprintw(Lines
++, 0, "%s sapped %.0f of your energy.",
672 Player
.p_energy
-= inflict
;
676 /* take all metal treasures */
678 "%s took all your metal treasures!", Enemyname
);
687 /* (large) poison and take a quickness */
689 "%s poisoned you, and took one quik.", Enemyname
);
690 Player
.p_poison
+= 5.0;
691 Player
.p_quickness
-= 1.0;
695 /* fly away, and leave either a Jubjub bird or Bonnacon */
697 "%s flew away, and left you to contend with one of its friends.",
699 Whichmonster
= 55 + (drandom() > 0.5) ? 22 : 0;
700 longjmp(Fightenv
, 0);
704 /* partially regenerate monster */
706 "%s partially regenerated his energy.!", Enemyname
);
707 Curmonster
.m_energy
+=
708 floor((Curmonster
.m_o_energy
- Curmonster
.m_energy
) / 2.0);
709 Curmonster
.m_strength
= Curmonster
.m_o_strength
;
710 Curmonster
.m_melee
= Curmonster
.m_skirmish
= 0.0;
711 Curmonster
.m_maxspeed
= Curmonster
.m_o_speed
;
715 if (!Player
.p_blindness
)
718 mvprintw(Lines
++, 0, "%s blinded you!", Enemyname
);
719 Player
.p_blindness
= TRUE
;
720 Enemyname
= "A monster";
727 /* fall through to here if monster inflicts a normal hit */
728 inflict
= drandom() * Curmonster
.m_strength
+ 0.5;
730 mvprintw(Lines
++, 0, "%s hit you %.0f times!", Enemyname
, inflict
);
732 if ((Shield
-= inflict
) < 0)
734 Player
.p_energy
+= Shield
;
739 /************************************************************************
741 / FUNCTION NAME: cancelmonster()
743 / FUNCTION: mark current monster as no longer active
745 / AUTHOR: E. A. Estes, 12/4/85
751 / MODULES CALLED: none
753 / GLOBAL INPUTS: none
755 / GLOBAL OUTPUTS: Curmonster
758 / Clear current monster's energy, experience, treasure type, and
759 / flock. This is the same as having the monster run away.
761 *************************************************************************/
766 Curmonster
.m_energy
= 0.0;
767 Curmonster
.m_experience
= 0.0;
768 Curmonster
.m_treasuretype
= 0;
769 Curmonster
.m_flock
= 0.0;
772 /************************************************************************
774 / FUNCTION NAME: hitmonster()
776 / FUNCTION: inflict damage upon current monster
778 / AUTHOR: E. A. Estes, 12/4/85
781 / double inflict - damage to inflict upon monster
785 / MODULES CALLED: monsthits(), wmove(), strcmp(), waddstr(), mvprintw()
787 / GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, *Enemyname
789 / GLOBAL OUTPUTS: Curmonster, Lines
792 / Hit monster specified number of times. Handle when monster dies,
793 / and a few special monsters.
795 *************************************************************************/
798 hitmonster(double inflict
)
800 mvprintw(Lines
++, 0, "You hit %s %.0f times!", Enemyname
, inflict
);
801 Curmonster
.m_energy
-= inflict
;
802 if (Curmonster
.m_energy
> 0.0)
804 if (Curmonster
.m_type
== SM_DARKLORD
|| Curmonster
.m_type
== SM_SHRIEKER
)
805 /* special monster didn't die */
809 /* monster died. print message. */
811 if (Curmonster
.m_type
== SM_MORGOTH
)
812 mvaddstr(Lines
++, 0, "You have defeated Morgoth, but he may return. . .");
814 /* all other types of monsters */
816 mvprintw(Lines
++, 0, "You killed it. Good work, %s.", Player
.p_name
);
818 if (Curmonster
.m_type
== SM_MIMIC
819 && strcmp(Curmonster
.m_name
, "A Mimic") != 0
820 && !Player
.p_blindness
)
821 mvaddstr(Lines
++, 0, "The body slowly changes into the form of a mimic.");
826 /************************************************************************
828 / FUNCTION NAME: throwspell()
830 / FUNCTION: throw a magic spell
832 / AUTHOR: E. A. Estes, 12/4/85
838 / MODULES CALLED: hitmonster(), cancelmonster(), sqrt(), floor(), wmove(),
839 / drandom(), altercoordinates(), longjmp(), infloat(), waddstr(), mvprintw(),
842 / GLOBAL INPUTS: Curmonster, Whichmonster, Nomana[], Player, *stdscr,
843 / Fightenv[], Illspell[], *Enemyname
845 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Shield, Player
848 / Prompt player and process magic spells.
850 *************************************************************************/
855 double inflict
= 0; /* damage inflicted */
856 double dtemp
; /* for dtemporary calculations */
859 mvaddstr(7, 0, "\n\n"); /* clear menu area */
861 if (Player
.p_magiclvl
>= ML_ALLORNOTHING
)
862 mvaddstr(7, 0, "1:All or Nothing ");
863 if (Player
.p_magiclvl
>= ML_MAGICBOLT
)
864 addstr("2:Magic Bolt ");
865 if (Player
.p_magiclvl
>= ML_FORCEFIELD
)
866 addstr("3:Force Field ");
867 if (Player
.p_magiclvl
>= ML_XFORM
)
868 addstr("4:Transform ");
869 if (Player
.p_magiclvl
>= ML_INCRMIGHT
)
870 addstr("5:Increase Might\n");
871 if (Player
.p_magiclvl
>= ML_INVISIBLE
)
872 mvaddstr(8, 0, "6:Invisibility ");
873 if (Player
.p_magiclvl
>= ML_XPORT
)
874 addstr("7:Transport ");
875 if (Player
.p_magiclvl
>= ML_PARALYZE
)
876 addstr("8:Paralyze ");
877 if (Player
.p_specialtype
>= SC_COUNCIL
)
879 mvaddstr(4, 0, "Spell ? ");
881 ch
= getanswer(" ", TRUE
);
883 mvaddstr(7, 0, "\n\n"); /* clear menu area */
885 if (Curmonster
.m_type
== SM_MORGOTH
&& ch
!= '3')
886 /* can only throw force field against Morgoth */
891 case '1': /* all or nothing */
892 if (drandom() < 0.25)
895 inflict
= Curmonster
.m_energy
* 1.01 + 1.0;
897 if (Curmonster
.m_type
== SM_DARKLORD
)
898 /* all or nothing doesn't quite work against D. L. */
902 /* failure -- monster gets stronger and quicker */
904 Curmonster
.m_o_strength
= Curmonster
.m_strength
*= 2.0;
905 Curmonster
.m_maxspeed
*= 2.0;
906 Curmonster
.m_o_speed
*= 2.0;
908 /* paralyzed monsters wake up a bit */
909 Curmonster
.m_speed
= MAX(1.0, Curmonster
.m_speed
* 2.0);
912 if (Player
.p_mana
>= MM_ALLORNOTHING
)
913 /* take a mana if player has one */
914 Player
.p_mana
-= MM_ALLORNOTHING
;
919 case '2': /* magic bolt */
920 if (Player
.p_magiclvl
< ML_MAGICBOLT
)
925 /* prompt for amount to expend */
927 mvaddstr(4, 0, "How much mana for bolt? ");
928 dtemp
= floor(infloat());
930 while (dtemp
< 0.0 || dtemp
> Player
.p_mana
);
932 Player
.p_mana
-= dtemp
;
934 if (Curmonster
.m_type
== SM_DARKLORD
)
935 /* magic bolts don't work against D. L. */
938 inflict
= dtemp
* ROLL(15.0, sqrt(Player
.p_magiclvl
/ 3.0 + 1.0));
939 mvaddstr(5, 0, "Magic Bolt fired!\n");
944 case '3': /* force field */
945 if (Player
.p_magiclvl
< ML_FORCEFIELD
)
947 else if (Player
.p_mana
< MM_FORCEFIELD
)
951 Player
.p_mana
-= MM_FORCEFIELD
;
952 Shield
= (Player
.p_maxenergy
+ Player
.p_shield
) * 4.2 + 45.0;
953 mvaddstr(5, 0, "Force Field up.\n");
957 case '4': /* transform */
958 if (Player
.p_magiclvl
< ML_XFORM
)
960 else if (Player
.p_mana
< MM_XFORM
)
964 Player
.p_mana
-= MM_XFORM
;
965 Whichmonster
= (int) ROLL(0.0, 100.0);
966 longjmp(Fightenv
, 0);
971 case '5': /* increase might */
972 if (Player
.p_magiclvl
< ML_INCRMIGHT
)
974 else if (Player
.p_mana
< MM_INCRMIGHT
)
978 Player
.p_mana
-= MM_INCRMIGHT
;
980 (1.2 * (Player
.p_strength
+ Player
.p_sword
)
981 + 5.0 - Player
.p_might
) / 2.0;
982 mvprintw(5, 0, "New strength: %.0f\n", Player
.p_might
);
986 case '6': /* invisible */
987 if (Player
.p_magiclvl
< ML_INVISIBLE
)
989 else if (Player
.p_mana
< MM_INVISIBLE
)
993 Player
.p_mana
-= MM_INVISIBLE
;
995 (1.2 * (Player
.p_quickness
+ Player
.p_quksilver
)
996 + 5.0 - Player
.p_speed
) / 2.0;
997 mvprintw(5, 0, "New quickness: %.0f\n", Player
.p_speed
);
1001 case '7': /* transport */
1002 if (Player
.p_magiclvl
< ML_XPORT
)
1004 else if (Player
.p_mana
< MM_XPORT
)
1008 Player
.p_mana
-= MM_XPORT
;
1009 if (Player
.p_brains
+ Player
.p_magiclvl
1010 < Curmonster
.m_experience
/ 200.0 * drandom())
1012 mvaddstr(5, 0, "Transport backfired!\n");
1013 altercoordinates(0.0, 0.0, A_FAR
);
1018 mvprintw(5, 0, "%s is transported.\n", Enemyname
);
1019 if (drandom() < 0.3)
1020 /* monster didn't drop its treasure */
1021 Curmonster
.m_treasuretype
= 0;
1023 Curmonster
.m_energy
= 0.0;
1028 case '8': /* paralyze */
1029 if (Player
.p_magiclvl
< ML_PARALYZE
)
1031 else if (Player
.p_mana
< MM_PARALYZE
)
1035 Player
.p_mana
-= MM_PARALYZE
;
1036 if (Player
.p_magiclvl
>
1037 Curmonster
.m_experience
/ 1000.0 * drandom())
1039 mvprintw(5, 0, "%s is held.\n", Enemyname
);
1040 Curmonster
.m_speed
= -2.0;
1043 mvaddstr(5, 0, "Monster unaffected.\n");
1047 case '9': /* specify */
1048 if (Player
.p_specialtype
< SC_COUNCIL
)
1050 else if (Player
.p_mana
< MM_SPECIFY
)
1054 Player
.p_mana
-= MM_SPECIFY
;
1055 mvaddstr(5, 0, "Which monster do you want [0-99] ? ");
1056 Whichmonster
= (int) infloat();
1057 Whichmonster
= MAX(0, MIN(99, Whichmonster
));
1058 longjmp(Fightenv
, 0);
1065 /************************************************************************
1067 / FUNCTION NAME: callmonster()
1069 / FUNCTION: read monster from file, and fill structure
1071 / AUTHOR: E. A. Estes, 2/25/86
1074 / int which - which monster to call
1076 / RETURN VALUE: none
1078 / MODULES CALLED: truncstring(), fread(), fseek(), floor(), drandom(),
1081 / GLOBAL INPUTS: Curmonster, Circle, Player, *Monstfp
1083 / GLOBAL OUTPUTS: Curmonster, Player, *Enemyname
1086 / Read specified monster from monster database and fill up
1087 / current monster structure.
1088 / Adjust statistics based upon current size.
1089 / Handle some special monsters.
1091 *************************************************************************/
1094 callmonster(int which
)
1096 struct monster Othermonster
; /* to find a name for mimics */
1098 which
= MIN(which
, 99); /* make sure within range */
1100 /* fill structure */
1101 fseek(Monstfp
, (long) which
* (long) SZ_MONSTERSTRUCT
, 0);
1102 fread((char *) &Curmonster
, SZ_MONSTERSTRUCT
, 1, Monstfp
);
1104 /* handle some special monsters */
1105 if (Curmonster
.m_type
== SM_MODNAR
)
1107 if (Player
.p_specialtype
< SC_COUNCIL
)
1108 /* randomize some stats */
1110 Curmonster
.m_strength
*= drandom() + 0.5;
1111 Curmonster
.m_brains
*= drandom() + 0.5;
1112 Curmonster
.m_speed
*= drandom() + 0.5;
1113 Curmonster
.m_energy
*= drandom() + 0.5;
1114 Curmonster
.m_experience
*= drandom() + 0.5;
1115 Curmonster
.m_treasuretype
=
1116 (int) ROLL(0.0, (double) Curmonster
.m_treasuretype
);
1119 /* make Modnar into Morgoth */
1121 strcpy(Curmonster
.m_name
, "Morgoth");
1122 Curmonster
.m_strength
= drandom() * (Player
.p_maxenergy
+ Player
.p_shield
) / 1.4
1123 + drandom() * (Player
.p_maxenergy
+ Player
.p_shield
) / 1.5;
1124 Curmonster
.m_brains
= Player
.p_brains
;
1125 Curmonster
.m_energy
= Player
.p_might
* 30.0;
1126 Curmonster
.m_type
= SM_MORGOTH
;
1127 Curmonster
.m_speed
= Player
.p_speed
* 1.1
1128 + (Player
.p_specialtype
== SC_EXVALAR
) ? Player
.p_speed
: 0.0;
1129 Curmonster
.m_flock
= 0.0;
1130 Curmonster
.m_treasuretype
= 0;
1131 Curmonster
.m_experience
= 0.0;
1134 else if (Curmonster
.m_type
== SM_MIMIC
)
1135 /* pick another name */
1137 which
= (int) ROLL(0.0, 100.0);
1138 fseek(Monstfp
, (long) which
* (long) SZ_MONSTERSTRUCT
, 0);
1139 fread(&Othermonster
, SZ_MONSTERSTRUCT
, 1, Monstfp
);
1140 strcpy(Curmonster
.m_name
, Othermonster
.m_name
);
1143 truncstring(Curmonster
.m_name
);
1145 if (Curmonster
.m_type
!= SM_MORGOTH
)
1146 /* adjust stats based on which circle player is in */
1148 Curmonster
.m_strength
*= (1.0 + Circle
/ 2.0);
1149 Curmonster
.m_brains
*= Circle
;
1150 Curmonster
.m_speed
+= Circle
* 1.e
-9;
1151 Curmonster
.m_energy
*= Circle
;
1152 Curmonster
.m_experience
*= Circle
;
1155 if (Player
.p_blindness
)
1156 /* cannot see monster if blind */
1157 Enemyname
= "A monster";
1159 Enemyname
= Curmonster
.m_name
;
1161 if (Player
.p_speed
<= 0.0)
1162 /* make Player.p_speed positive */
1164 Curmonster
.m_speed
+= -Player
.p_speed
;
1165 Player
.p_speed
= 1.0;
1168 /* fill up the rest of the structure */
1169 Curmonster
.m_o_strength
= Curmonster
.m_strength
;
1170 Curmonster
.m_o_speed
= Curmonster
.m_maxspeed
= Curmonster
.m_speed
;
1171 Curmonster
.m_o_energy
= Curmonster
.m_energy
;
1172 Curmonster
.m_melee
= Curmonster
.m_skirmish
= 0.0;
1175 /************************************************************************
1177 / FUNCTION NAME: awardtreasure()
1179 / FUNCTION: select a treasure
1181 / AUTHOR: E. A. Estes, 12/4/85
1185 / RETURN VALUE: none
1187 / MODULES CALLED: pickmonster(), collecttaxes(), more(), cursedtreasure(),
1188 / floor(), wmove(), drandom(), sscanf(), printw(), altercoordinates(),
1189 / longjmp(), infloat(), waddstr(), getanswer(), getstring(), wclrtobot()
1191 / GLOBAL INPUTS: Somebetter[], Curmonster, Whichmonster, Circle, Player,
1192 / *stdscr, Databuf[], *Statptr, Fightenv[]
1194 / GLOBAL OUTPUTS: Whichmonster, Shield, Player
1197 / Roll up a treasure based upon monster type and size, and
1198 / certain player statistics.
1199 / Handle cursed treasure.
1201 *************************************************************************/
1206 int whichtreasure
; /* calculated treasure to grant */
1207 int temp
; /* temporary */
1209 double treasuretype
; /* monster's treasure type */
1210 double gold
= 0.0; /* gold awarded */
1211 double gems
= 0.0; /* gems awarded */
1212 double dtemp
; /* for temporary calculations */
1214 whichtreasure
= (int) ROLL(1.0, 3.0); /* pick a treasure */
1215 treasuretype
= (double) Curmonster
.m_treasuretype
;
1221 if (drandom() > 0.65)
1224 if (Curmonster
.m_treasuretype
> 7)
1227 gems
= ROLL(1.0, (treasuretype
- 7.0)
1228 * (treasuretype
- 7.0) * (Circle
- 1.0) / 4.0);
1229 printw("You have discovered %.0f gems!", gems
);
1234 gold
= ROLL(treasuretype
* 10.0, treasuretype
1235 * treasuretype
* 10.0 * (Circle
- 1.0));
1236 printw("You have found %.0f gold pieces.", gold
);
1239 addstr(" Do you want to pick them up ? ");
1240 ch
= getanswer("NY", FALSE
);
1244 if (drandom() < treasuretype
/ 35.0 + 0.04)
1247 addstr("They were cursed!\n");
1251 collecttaxes(gold
, gems
);
1257 /* other treasures */
1259 addstr("You have found some treasure. Do you want to inspect it ? ");
1260 ch
= getanswer("NY", FALSE
);
1266 if (drandom() < 0.08 && Curmonster
.m_treasuretype
!= 4)
1268 addstr("It was cursed!\n");
1273 switch (Curmonster
.m_treasuretype
)
1275 case 1: /* treasure type 1 */
1276 switch (whichtreasure
)
1279 addstr("You've discovered a power booster!\n");
1280 Player
.p_mana
+= ROLL(Circle
* 4.0, Circle
* 30.0);
1284 addstr("You have encountered a druid.\n");
1285 Player
.p_experience
+=
1286 ROLL(0.0, 2000.0 + Circle
* 400.0);
1290 addstr("You have found a holy orb.\n");
1291 Player
.p_sin
= MAX(0.0, Player
.p_sin
- 0.25);
1295 /* end treasure type 1 */
1297 case 2: /* treasure type 2 */
1298 switch (whichtreasure
)
1301 addstr("You have found an amulet.\n");
1306 addstr("You've found some holy water!\n");
1307 ++Player
.p_holywater
;
1311 addstr("You've met a hermit!\n");
1312 Player
.p_sin
*= 0.75;
1313 Player
.p_mana
+= 12.0 * Circle
;
1317 /* end treasure type 2 */
1319 case 3: /* treasure type 3 */
1320 switch (whichtreasure
)
1323 dtemp
= ROLL(7.0, 30.0 + Circle
/ 10.0);
1324 printw("You've found a +%.0f shield!\n", dtemp
);
1325 if (dtemp
>= Player
.p_shield
)
1326 Player
.p_shield
= dtemp
;
1332 addstr("You have rescued a virgin. Will you be honorable ? ");
1333 ch
= getanswer("NY", FALSE
);
1336 Player
.p_virgin
= TRUE
;
1339 Player
.p_experience
+= 2000.0 * Circle
;
1345 addstr("You've discovered some athelas!\n");
1350 /* end treasure type 3 */
1352 case 4: /* treasure type 4 */
1353 addstr("You've found a scroll. Will you read it ? ");
1354 ch
= getanswer("NY", FALSE
);
1358 switch ((int) ROLL(1, 6))
1361 addstr("It throws up a shield for you next monster.\n");
1362 getyx(stdscr
, whichtreasure
, ch
);
1363 more(whichtreasure
);
1365 (Player
.p_maxenergy
+ Player
.p_energy
) * 5.5 + Circle
* 50.0;
1366 Whichmonster
= pickmonster();
1367 longjmp(Fightenv
, 0);
1371 addstr("It makes you invisible for you next monster.\n");
1372 getyx(stdscr
, whichtreasure
, ch
);
1373 more(whichtreasure
);
1374 Player
.p_speed
= 1e6
;
1375 Whichmonster
= pickmonster();
1376 longjmp(Fightenv
, 0);
1380 addstr("It increases your strength ten fold to fight your next monster.\n");
1381 getyx(stdscr
, whichtreasure
, ch
);
1382 more(whichtreasure
);
1383 Player
.p_might
*= 10.0;
1384 Whichmonster
= pickmonster();
1385 longjmp(Fightenv
, 0);
1389 addstr("It is a general knowledge scroll.\n");
1390 Player
.p_brains
+= ROLL(2.0, Circle
);
1391 Player
.p_magiclvl
+= ROLL(1.0, Circle
/ 2.0);
1395 addstr("It tells you how to pick your next monster.\n");
1396 addstr("Which monster do you want [0-99] ? ");
1397 Whichmonster
= (int) infloat();
1398 Whichmonster
= MIN(99, MAX(0, Whichmonster
));
1399 longjmp(Fightenv
, 0);
1402 addstr("It was cursed!\n");
1407 /* end treasure type 4 */
1409 case 5: /* treasure type 5 */
1410 switch (whichtreasure
)
1413 dtemp
= ROLL(Circle
/ 4.0 + 5.0, Circle
/ 2.0 + 9.0);
1414 printw("You've discovered a +%.0f dagger.\n", dtemp
);
1415 if (dtemp
>= Player
.p_sword
)
1416 Player
.p_sword
= dtemp
;
1422 dtemp
= ROLL(7.5 + Circle
* 3.0, Circle
* 2.0 + 160.0);
1423 printw("You have found some +%.0f armour!\n", dtemp
);
1424 if (dtemp
>= Player
.p_shield
)
1425 Player
.p_shield
= dtemp
;
1431 addstr("You've found a tablet.\n");
1432 Player
.p_brains
+= 4.5 * Circle
;
1436 /* end treasure type 5 */
1438 case 6: /* treasure type 6 */
1439 switch (whichtreasure
)
1442 addstr("You've found a priest.\n");
1443 Player
.p_energy
= Player
.p_maxenergy
+ Player
.p_shield
;
1444 Player
.p_sin
/= 2.0;
1445 Player
.p_mana
+= 24.0 * Circle
;
1446 Player
.p_brains
+= Circle
;
1450 addstr("You have come upon Robin Hood!\n");
1451 Player
.p_shield
+= Circle
* 2.0;
1452 Player
.p_strength
+= Circle
/ 2.5 + 1.0;
1456 dtemp
= ROLL(2.0 + Circle
/ 4.0, Circle
/ 1.2 + 10.0);
1457 printw("You have found a +%.0f axe!\n", dtemp
);
1458 if (dtemp
>= Player
.p_sword
)
1459 Player
.p_sword
= dtemp
;
1465 /* end treasure type 6 */
1467 case 7: /* treasure type 7 */
1468 switch (whichtreasure
)
1471 addstr("You've discovered a charm!\n");
1476 addstr("You have encountered Merlyn!\n");
1477 Player
.p_brains
+= Circle
+ 5.0;
1478 Player
.p_magiclvl
+= Circle
/ 3.0 + 5.0;
1479 Player
.p_mana
+= Circle
* 10.0;
1483 dtemp
= ROLL(5.0 + Circle
/ 3.0, Circle
/ 1.5 + 20.0);
1484 printw("You have found a +%.0f war hammer!\n", dtemp
);
1485 if (dtemp
>= Player
.p_sword
)
1486 Player
.p_sword
= dtemp
;
1492 /* end treasure type 7 */
1494 case 8: /* treasure type 8 */
1495 switch (whichtreasure
)
1498 addstr("You have found a healing potion.\n");
1499 Player
.p_poison
= MIN(-2.0, Player
.p_poison
- 2.0);
1503 addstr("You have discovered a transporter. Do you wish to go anywhere ? ");
1504 ch
= getanswer("NY", FALSE
);
1510 addstr("X Y Coordinates ? ");
1511 getstring(Databuf
, SZ_DATABUF
);
1512 sscanf(Databuf
, "%lf %lf", &x
, &y
);
1513 altercoordinates(x
, y
, A_FORCED
);
1518 dtemp
= ROLL(10.0 + Circle
/ 1.2, Circle
* 3.0 + 30.0);
1519 printw("You've found a +%.0f sword!\n", dtemp
);
1520 if (dtemp
>= Player
.p_sword
)
1521 Player
.p_sword
= dtemp
;
1527 /* end treasure type 8 */
1532 case 13: /* treasure types 10 - 13 */
1533 if (drandom() < 0.33)
1535 if (Curmonster
.m_treasuretype
== 10)
1537 addstr("You've found a pair of elven boots!\n");
1538 Player
.p_quickness
+= 2.0;
1541 else if (Curmonster
.m_treasuretype
== 11
1542 && !Player
.p_palantir
)
1544 addstr("You've acquired Saruman's palantir.\n");
1545 Player
.p_palantir
= TRUE
;
1548 else if (Player
.p_ring
.ring_type
== R_NONE
1549 && Player
.p_specialtype
< SC_COUNCIL
1550 && (Curmonster
.m_treasuretype
== 12
1551 || Curmonster
.m_treasuretype
== 13))
1552 /* roll up a ring */
1554 if (drandom() < 0.8)
1557 if (Curmonster
.m_treasuretype
== 12)
1559 whichtreasure
= R_NAZREG
;
1564 whichtreasure
= R_DLREG
;
1571 whichtreasure
= R_BAD
;
1572 temp
= 15 + Statptr
->c_ringduration
+ (int) ROLL(0,5);
1575 addstr("You've discovered a ring. Will you pick it up ? ");
1576 ch
= getanswer("NY", FALSE
);
1581 Player
.p_ring
.ring_type
= whichtreasure
;
1582 Player
.p_ring
.ring_duration
= temp
;
1588 /* end treasure types 10 - 13 */
1589 /* fall through to treasure type 9 if no treasure from above */
1591 case 9: /* treasure type 9 */
1592 switch (whichtreasure
)
1595 if (Player
.p_level
<= 1000.0
1596 && Player
.p_crowns
<= 3
1597 && Player
.p_level
>= 10.0)
1599 addstr("You have found a golden crown!\n");
1603 /* fall through otherwise */
1606 addstr("You've been blessed!\n");
1607 Player
.p_blessing
= TRUE
;
1608 Player
.p_sin
/= 3.0;
1609 Player
.p_energy
= Player
.p_maxenergy
+ Player
.p_shield
;
1610 Player
.p_mana
+= 100.0 * Circle
;
1614 dtemp
= ROLL(1.0, Circle
/ 5.0 + 5.0);
1615 dtemp
= MIN(dtemp
, 99.0);
1616 printw("You have discovered some +%.0f quicksilver!\n",dtemp
);
1617 if (dtemp
>= Player
.p_quksilver
)
1618 Player
.p_quksilver
= dtemp
;
1624 /* end treasure type 9 */
1629 /************************************************************************
1631 / FUNCTION NAME: cursedtreasure()
1633 / FUNCTION: take care of cursed treasure
1635 / AUTHOR: E. A. Estes, 12/4/85
1639 / RETURN VALUE: none
1641 / MODULES CALLED: waddstr()
1643 / GLOBAL INPUTS: Player, *stdscr
1645 / GLOBAL OUTPUTS: Player
1648 / Handle cursed treasure. Look for amulets and charms to save
1649 / the player from the curse.
1651 *************************************************************************/
1654 cursedtreasure(void)
1656 if (Player
.p_charms
> 0)
1658 addstr("But your charm saved you!\n");
1661 else if (Player
.p_amulets
> 0)
1663 addstr("But your amulet saved you!\n");
1668 Player
.p_energy
= (Player
.p_maxenergy
+ Player
.p_shield
) / 10.0;
1669 Player
.p_poison
+= 0.25;
1673 /************************************************************************
1675 / FUNCTION NAME: scramblestats()
1677 / FUNCTION: scramble some selected statistics
1679 / AUTHOR: E. A. Estes, 12/4/85
1683 / RETURN VALUE: none
1685 / MODULES CALLED: floor(), drandom()
1687 / GLOBAL INPUTS: Player
1689 / GLOBAL OUTPUTS: Player
1692 / Swap a few player statistics randomly.
1694 *************************************************************************/
1699 double dbuf
[6]; /* to put statistic in */
1700 double dtemp1
, dtemp2
; /* for swapping values */
1701 int first
, second
; /* indices for swapping */
1702 double *dptr
; /* pointer for filling and emptying buf[] */
1706 *dptr
++ = Player
.p_strength
;
1707 *dptr
++ = Player
.p_mana
;
1708 *dptr
++ = Player
.p_brains
;
1709 *dptr
++ = Player
.p_magiclvl
;
1710 *dptr
++ = Player
.p_energy
;
1711 *dptr
= Player
.p_sin
;
1713 /* pick values to swap */
1714 first
= (int) ROLL(0, 5);
1715 second
= (int) ROLL(0, 5);
1719 dtemp1
= dptr
[first
];
1720 /* this expression is split to prevent a compiler loop on some compilers */
1721 dtemp2
= dptr
[second
];
1722 dptr
[first
] = dtemp2
;
1723 dptr
[second
] = dtemp1
;
1726 Player
.p_strength
= *dptr
++;
1727 Player
.p_mana
= *dptr
++;
1728 Player
.p_brains
= *dptr
++;
1729 Player
.p_magiclvl
= *dptr
++;
1730 Player
.p_energy
= *dptr
++;
1731 Player
.p_sin
= *dptr
;