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.2 2003/06/17 04:25:24 dillon Exp $
11 /************************************************************************
13 / FUNCTION NAME: encounter()
15 / FUNCTION: monster battle routine
17 / AUTHOR: E. A. Estes, 2/20/86
20 / int particular - particular monster to fight if >= 0
24 / MODULES CALLED: monsthits(), playerhits(), readmessage(), callmonster(),
25 / writerecord(), pickmonster(), displaystats(), pow(), cancelmonster(),
26 / awardtreasure(), more(), death(), wmove(), setjmp(), drandom(), printw(),
27 / longjmp(), wrefresh(), mvprintw(), wclrtobot()
29 / GLOBAL INPUTS: Curmonster, Whichmonster, LINES, Lines, Circle, Shield,
30 / Player, *stdscr, Fileloc, Fightenv[], *Enemyname
32 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player, Luckout
35 / Choose a monster and check against some special types.
36 / Arbitrate between monster and player. Watch for either
39 *************************************************************************/
44 bool firsthit = Player.p_blessing; /* set if player gets the first hit */
45 int flockcnt = 1; /* how many time flocked */
47 /* let others know what we are doing */
48 Player.p_status = S_MONSTER;
49 writerecord(&Player, Fileloc);
55 Shield = 0.0; /* no shield up yet */
58 /* monster is specified */
59 Whichmonster = particular;
61 /* pick random monster */
62 Whichmonster = pickmonster();
64 setjmp(Fightenv); /* this is to enable changing fight state */
67 clrtobot(); /* clear bottom area of screen */
70 callmonster(Whichmonster); /* set up monster to fight */
72 Luckout = FALSE; /* haven't tried to luckout yet */
74 if (Curmonster.m_type == SM_MORGOTH)
75 mvprintw(4, 0, "You've encountered %s, Bane of the Council and Valar.\n",
78 if (Curmonster.m_type == SM_UNICORN)
82 printw("You just subdued %s, thanks to the virgin.\n", Enemyname);
83 Player.p_virgin = FALSE;
87 printw("You just saw %s running away!\n", Enemyname);
88 Curmonster.m_experience = 0.0;
89 Curmonster.m_treasuretype = 0;
93 /* not a special monster */
95 /* print header, and arbitrate between player and monster */
97 mvprintw(6, 0, "You are being attacked by %s, EXP: %.0f (Size: %.0f)\n",
98 Enemyname, Curmonster.m_experience, Circle);
101 mvprintw(1, 26, "%20.0f", Player.p_energy + Shield); /* overprint energy */
104 if (Curmonster.m_type == SM_DARKLORD
106 && Player.p_charms > 0)
107 /* overpower Dark Lord with blessing and charm */
109 mvprintw(7, 0, "You just overpowered %s!", Enemyname);
111 Player.p_blessing = FALSE;
116 /* allow paralyzed monster to wake up */
117 Curmonster.m_speed = MIN(Curmonster.m_speed + 1.0, Curmonster.m_maxspeed);
119 if (drandom() * Curmonster.m_speed > drandom() * Player.p_speed
120 /* monster is faster */
121 && Curmonster.m_type != SM_DARKLORD
123 && Curmonster.m_type != SM_SHRIEKER
126 /* monster gets a hit */
129 /* player gets a hit */
137 if (Lines > LINES - 2)
138 /* near bottom of screen - pause */
145 if (Player.p_energy <= 0.0)
151 break; /* fight ends if the player is saved from death */
154 if (Curmonster.m_energy <= 0.0)
159 /* give player credit for killing monster */
160 Player.p_experience += Curmonster.m_experience;
162 if (drandom() < Curmonster.m_flock / 100.0)
167 longjmp(Fightenv, 0);
170 else if (Circle > 1.0
171 && Curmonster.m_treasuretype > 0
172 && drandom() > 0.2 + pow(0.4, (double) (flockcnt / 3 + Circle / 3.0)))
173 /* monster has treasure; this takes # of flocks and size into account */
179 /* pause before returning */
180 getyx(stdscr, Lines, flockcnt);
183 Player.p_ring.ring_inuse = FALSE; /* not using ring */
185 /* clean up the screen */
190 /************************************************************************
192 / FUNCTION NAME: pickmonster()
194 / FUNCTION: choose a monster based upon where we are
196 / AUTHOR: E. A. Estes, 2/20/86
200 / RETURN VALUE: monster number to call
202 / MODULES CALLED: floor(), drandom()
204 / GLOBAL INPUTS: Marsh, Circle, Player
206 / GLOBAL OUTPUTS: none
209 / Certain monsters can be found in certain areas of the grid.
210 / We take care of rolling them here.
211 / Unfortunately, this routine assumes that the monster data
212 / base is arranged in a particular order. If the data base
213 / is altered (to add monsters, or make them tougher), this
214 / routine may also need to be changed.
216 *************************************************************************/
220 if (Player.p_specialtype == SC_VALAR)
221 /* even chance of any monster */
222 return((int) ROLL(0.0, 100.0));
226 return((int) ROLL(0.0, 15.0));
228 else if (Circle > 24)
229 /* even chance of all non-water monsters */
230 return((int) ROLL(14.0, 86.0));
232 else if (Circle > 15)
233 /* chance of all non-water monsters, weighted toward middle */
234 return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 37.0)));
237 /* not all non-water monsters, weighted toward middle */
238 return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 26.0)));
241 /* even chance of some tamer non-water monsters */
242 return((int) ROLL(14.0, 50.0));
245 /* even chance of some of the tamest non-water monsters */
246 return((int) ROLL(14.0, 25.0));
249 /************************************************************************
251 / FUNCTION NAME: playerhits()
253 / FUNCTION: prompt player for action in monster battle, and process
255 / AUTHOR: E. A. Estes, 12/4/85
261 / MODULES CALLED: hitmonster(), throwspell(), inputoption(), cancelmonster(),
262 / floor(), wmove(), drandom(), altercoordinates(), waddstr(), mvprintw(),
263 / wclrtoeol(), wclrtobot()
265 / GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, Luckout, *Enemyname
267 / GLOBAL OUTPUTS: Curmonster, Lines, Player, Luckout
270 / Process all monster battle options.
272 *************************************************************************/
276 double inflict; /* damage inflicted */
279 mvaddstr(7, 0, "1:Melee 2:Skirmish 3:Evade 4:Spell 5:Nick ");
282 /* haven't tried to luckout yet */
283 if (Curmonster.m_type == SM_MORGOTH)
284 /* cannot luckout against Morgoth */
287 addstr("6:Luckout ");
290 if (Player.p_ring.ring_type != R_NONE)
291 /* player has a ring */
292 addstr("7:Use Ring ");
299 clrtobot(); /* clear any messages from before */
301 mvaddstr(4, 0, "\n\n"); /* clear status area */
305 case 'T': /* timeout; lose turn */
309 case '1': /* melee */
310 /* melee affects monster's energy and strength */
311 inflict = ROLL(Player.p_might / 2.0 + 5.0, 1.3 * Player.p_might)
312 + (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
314 Curmonster.m_melee += inflict;
315 Curmonster.m_strength = Curmonster.m_o_strength
316 - Curmonster.m_melee / Curmonster.m_o_energy
317 * Curmonster.m_o_strength / 4.0;
321 case '2': /* skirmish */
322 /* skirmish affects monter's energy and speed */
323 inflict = ROLL(Player.p_might / 3.0 + 3.0, 1.1 * Player.p_might)
324 + (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
326 Curmonster.m_skirmish += inflict;
327 Curmonster.m_maxspeed = Curmonster.m_o_speed
328 - Curmonster.m_skirmish / Curmonster.m_o_energy
329 * Curmonster.m_o_speed / 4.0;
333 case '3': /* evade */
334 /* use brains and speed to try to evade */
335 if ((Curmonster.m_type == SM_DARKLORD
336 || Curmonster.m_type == SM_SHRIEKER
337 /* can always run from D. L. and shrieker */
338 || drandom() * Player.p_speed * Player.p_brains
339 > drandom() * Curmonster.m_speed * Curmonster.m_brains)
340 && (Curmonster.m_type != SM_MIMIC))
341 /* cannot run from mimic */
343 mvaddstr(Lines++, 0, "You got away!");
345 altercoordinates(0.0, 0.0, A_NEAR);
348 mvprintw(Lines++, 0, "%s is still after you!", Enemyname);
353 case '4': /* magic spell */
358 /* hit 1 plus sword; give some experience */
359 inflict = 1.0 + Player.p_sword;
360 Player.p_experience += floor(Curmonster.m_experience / 10.0);
361 Curmonster.m_experience *= 0.92;
362 /* monster gets meaner */
363 Curmonster.m_maxspeed += 2.0;
364 Curmonster.m_speed = (Curmonster.m_speed < 0.0) ? 0.0 : Curmonster.m_speed + 2.0;
365 if (Curmonster.m_type == SM_DARKLORD)
366 /* Dark Lord; doesn't like to be nicked */
369 "You hit %s %.0f times, and made him mad!", Enemyname, inflict);
370 Player.p_quickness /= 2.0;
371 altercoordinates(0.0, 0.0, A_FAR);
379 case '6': /* luckout */
381 mvaddstr(Lines++, 0, "You already tried that.");
385 if (Curmonster.m_type == SM_MORGOTH)
388 if (drandom() < Player.p_sin / 100.0)
390 mvprintw(Lines++, 0, "%s accepted!", Enemyname);
394 mvaddstr(Lines++, 0, "Nope, he's not interested.");
397 /* normal monster; use brains for success */
399 if ((drandom() + 0.333) * Player.p_brains
400 < (drandom() + 0.333) * Curmonster.m_brains)
401 mvprintw(Lines++, 0, "You blew it, %s.", Player.p_name);
404 mvaddstr(Lines++, 0, "You made it!");
405 Curmonster.m_energy = 0.0;
411 case '7': /* use ring */
412 if (Player.p_ring.ring_type != R_NONE)
414 mvaddstr(Lines++, 0, "Now using ring.");
415 Player.p_ring.ring_inuse = TRUE;
416 if (Player.p_ring.ring_type != R_DLREG)
418 --Player.p_ring.ring_duration;
425 /************************************************************************
427 / FUNCTION NAME: monsthits()
429 / FUNCTION: process a monster hitting the player
431 / AUTHOR: E. A. Estes, 12/4/85
437 / MODULES CALLED: cancelmonster(), scramblestats(), more(), floor(), wmove(),
438 / drandom(), altercoordinates(), longjmp(), waddstr(), mvprintw(),
441 / GLOBAL INPUTS: Curmonster, Lines, Circle, Shield, Player, *stdscr,
442 / Fightenv[], *Enemyname
444 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player,
448 / Handle all special monsters here. If the monster is not a special
449 / one, simply roll a hit against the player.
451 *************************************************************************/
455 double inflict; /* damage inflicted */
458 switch (Curmonster.m_type)
459 /* may be a special monster */
462 /* hits just enough to kill player */
463 inflict = (Player.p_energy + Shield) * 1.02;
467 /* call a big monster */
469 "Shrieeeek!! You scared it, and it called one of its friends.");
471 Whichmonster = (int) ROLL(70.0, 30.0);
472 longjmp(Fightenv, 0);
476 /* take experience away */
477 inflict = ROLL(10.0, Curmonster.m_strength);
478 inflict = MIN(Player.p_experience, inflict);
480 "%s took away %.0f experience points.", Enemyname, inflict);
481 Player.p_experience -= inflict;
485 if (Player.p_holywater > 0)
486 /* holy water kills when monster tries to hit */
488 mvprintw(Lines++, 0, "Your holy water killed it!");
489 --Player.p_holywater;
490 Curmonster.m_energy = 0.0;
504 /* else special things */
505 switch (Curmonster.m_type)
508 /* takes some of the player's strength */
509 inflict = ROLL(1.0, (Circle - 1.0) / 2.0);
510 inflict = MIN(Player.p_strength, inflict);
511 mvprintw(Lines++, 0, "%s sapped %0.f of your strength!",
513 Player.p_strength -= inflict;
514 Player.p_might -= inflict;
518 if (Player.p_palantir)
519 /* take away palantir */
521 mvprintw(Lines++, 0, "Wormtongue stole your palantir!");
522 Player.p_palantir = FALSE;
524 else if (drandom() > 0.5)
525 /* gems turn to gold */
528 "%s transformed your gems into gold!", Enemyname);
529 Player.p_gold += Player.p_gems;
533 /* scramble some stats */
535 mvprintw(Lines++, 0, "%s scrambled your stats!", Enemyname);
541 /* transport player */
542 mvprintw(Lines++, 0, "%s transported you!", Enemyname);
543 altercoordinates(0.0, 0.0, A_FAR);
548 /* suck up some mana */
549 inflict = ROLL(0, 7.5 * Circle);
550 inflict = MIN(Player.p_mana, floor(inflict));
552 "%s sucked up %.0f of your mana!", Enemyname, inflict);
553 Player.p_mana -= inflict;
557 /* try to take ring if player has one */
558 if (Player.p_ring.ring_type != R_NONE)
559 /* player has a ring */
561 mvaddstr(Lines++, 0, "Will you relinguish your ring ? ");
562 ch = getanswer("YN", FALSE);
566 Player.p_ring.ring_type = R_NONE;
567 Player.p_ring.ring_inuse = FALSE;
573 /* otherwise, take some brains */
575 "%s neutralized 1/5 of your brain!", Enemyname);
576 Player.p_brains *= 0.8;
580 /* take some gold and gems */
582 "%s took half your gold and gems and flew off.", Enemyname);
583 Player.p_gold /= 2.0;
584 Player.p_gems /= 2.0;
589 /* steal a gold piece and run */
591 "%s stole one gold piece and ran away.", Enemyname);
592 Player.p_gold = MAX(0.0, Player.p_gold - 1.0);
597 /* bite and (medium) poison */
599 "%s has bitten and poisoned you!", Enemyname);
600 Player.p_poison -= 1.0;
604 /* bite and (small) poison */
605 mvprintw(Lines++, 0, "%s bit and poisoned you!", Enemyname);
606 Player.p_poison += 0.25;
611 mvprintw(Lines++, 0, "%s farted and scampered off.", Enemyname);
612 Player.p_energy /= 2.0; /* damage from fumes */
617 if (Player.p_ring.ring_type != R_NONE)
618 /* try to steal ring */
621 "%s tried to steal your ring, ", Enemyname);
623 addstr("but was unsuccessful.");
626 addstr("and ran away with it!");
627 Player.p_ring.ring_type = R_NONE;
634 /* inflict damage through shield */
635 inflict = ROLL(15.0, Circle * 10.0);
636 inflict = MIN(inflict, Player.p_energy);
637 mvprintw(Lines++, 0, "%s sapped %.0f of your energy.",
639 Player.p_energy -= inflict;
643 /* take all metal treasures */
645 "%s took all your metal treasures!", Enemyname);
654 /* (large) poison and take a quickness */
656 "%s poisoned you, and took one quik.", Enemyname);
657 Player.p_poison += 5.0;
658 Player.p_quickness -= 1.0;
662 /* fly away, and leave either a Jubjub bird or Bonnacon */
664 "%s flew away, and left you to contend with one of its friends.",
666 Whichmonster = 55 + (drandom() > 0.5) ? 22 : 0;
667 longjmp(Fightenv, 0);
671 /* partially regenerate monster */
673 "%s partially regenerated his energy.!", Enemyname);
674 Curmonster.m_energy +=
675 floor((Curmonster.m_o_energy - Curmonster.m_energy) / 2.0);
676 Curmonster.m_strength = Curmonster.m_o_strength;
677 Curmonster.m_melee = Curmonster.m_skirmish = 0.0;
678 Curmonster.m_maxspeed = Curmonster.m_o_speed;
682 if (!Player.p_blindness)
685 mvprintw(Lines++, 0, "%s blinded you!", Enemyname);
686 Player.p_blindness = TRUE;
687 Enemyname = "A monster";
694 /* fall through to here if monster inflicts a normal hit */
695 inflict = drandom() * Curmonster.m_strength + 0.5;
697 mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, inflict);
699 if ((Shield -= inflict) < 0)
701 Player.p_energy += Shield;
706 /************************************************************************
708 / FUNCTION NAME: cancelmonster()
710 / FUNCTION: mark current monster as no longer active
712 / AUTHOR: E. A. Estes, 12/4/85
718 / MODULES CALLED: none
720 / GLOBAL INPUTS: none
722 / GLOBAL OUTPUTS: Curmonster
725 / Clear current monster's energy, experience, treasure type, and
726 / flock. This is the same as having the monster run away.
728 *************************************************************************/
732 Curmonster.m_energy = 0.0;
733 Curmonster.m_experience = 0.0;
734 Curmonster.m_treasuretype = 0;
735 Curmonster.m_flock = 0.0;
738 /************************************************************************
740 / FUNCTION NAME: hitmonster()
742 / FUNCTION: inflict damage upon current monster
744 / AUTHOR: E. A. Estes, 12/4/85
747 / double inflict - damage to inflict upon monster
751 / MODULES CALLED: monsthits(), wmove(), strcmp(), waddstr(), mvprintw()
753 / GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, *Enemyname
755 / GLOBAL OUTPUTS: Curmonster, Lines
758 / Hit monster specified number of times. Handle when monster dies,
759 / and a few special monsters.
761 *************************************************************************/
766 mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, inflict);
767 Curmonster.m_energy -= inflict;
768 if (Curmonster.m_energy > 0.0)
770 if (Curmonster.m_type == SM_DARKLORD || Curmonster.m_type == SM_SHRIEKER)
771 /* special monster didn't die */
775 /* monster died. print message. */
777 if (Curmonster.m_type == SM_MORGOTH)
778 mvaddstr(Lines++, 0, "You have defeated Morgoth, but he may return. . .");
780 /* all other types of monsters */
782 mvprintw(Lines++, 0, "You killed it. Good work, %s.", Player.p_name);
784 if (Curmonster.m_type == SM_MIMIC
785 && strcmp(Curmonster.m_name, "A Mimic") != 0
786 && !Player.p_blindness)
787 mvaddstr(Lines++, 0, "The body slowly changes into the form of a mimic.");
792 /************************************************************************
794 / FUNCTION NAME: throwspell()
796 / FUNCTION: throw a magic spell
798 / AUTHOR: E. A. Estes, 12/4/85
804 / MODULES CALLED: hitmonster(), cancelmonster(), sqrt(), floor(), wmove(),
805 / drandom(), altercoordinates(), longjmp(), infloat(), waddstr(), mvprintw(),
808 / GLOBAL INPUTS: Curmonster, Whichmonster, Nomana[], Player, *stdscr,
809 / Fightenv[], Illspell[], *Enemyname
811 / GLOBAL OUTPUTS: Curmonster, Whichmonster, Shield, Player
814 / Prompt player and process magic spells.
816 *************************************************************************/
820 double inflict; /* damage inflicted */
821 double dtemp; /* for dtemporary calculations */
824 mvaddstr(7, 0, "\n\n"); /* clear menu area */
826 if (Player.p_magiclvl >= ML_ALLORNOTHING)
827 mvaddstr(7, 0, "1:All or Nothing ");
828 if (Player.p_magiclvl >= ML_MAGICBOLT)
829 addstr("2:Magic Bolt ");
830 if (Player.p_magiclvl >= ML_FORCEFIELD)
831 addstr("3:Force Field ");
832 if (Player.p_magiclvl >= ML_XFORM)
833 addstr("4:Transform ");
834 if (Player.p_magiclvl >= ML_INCRMIGHT)
835 addstr("5:Increase Might\n");
836 if (Player.p_magiclvl >= ML_INVISIBLE)
837 mvaddstr(8, 0, "6:Invisibility ");
838 if (Player.p_magiclvl >= ML_XPORT)
839 addstr("7:Transport ");
840 if (Player.p_magiclvl >= ML_PARALYZE)
841 addstr("8:Paralyze ");
842 if (Player.p_specialtype >= SC_COUNCIL)
844 mvaddstr(4, 0, "Spell ? ");
846 ch = getanswer(" ", TRUE);
848 mvaddstr(7, 0, "\n\n"); /* clear menu area */
850 if (Curmonster.m_type == SM_MORGOTH && ch != '3')
851 /* can only throw force field against Morgoth */
856 case '1': /* all or nothing */
857 if (drandom() < 0.25)
860 inflict = Curmonster.m_energy * 1.01 + 1.0;
862 if (Curmonster.m_type == SM_DARKLORD)
863 /* all or nothing doesn't quite work against D. L. */
867 /* failure -- monster gets stronger and quicker */
869 Curmonster.m_o_strength = Curmonster.m_strength *= 2.0;
870 Curmonster.m_maxspeed *= 2.0;
871 Curmonster.m_o_speed *= 2.0;
873 /* paralyzed monsters wake up a bit */
874 Curmonster.m_speed = MAX(1.0, Curmonster.m_speed * 2.0);
877 if (Player.p_mana >= MM_ALLORNOTHING)
878 /* take a mana if player has one */
879 Player.p_mana -= MM_ALLORNOTHING;
884 case '2': /* magic bolt */
885 if (Player.p_magiclvl < ML_MAGICBOLT)
890 /* prompt for amount to expend */
892 mvaddstr(4, 0, "How much mana for bolt? ");
893 dtemp = floor(infloat());
895 while (dtemp < 0.0 || dtemp > Player.p_mana);
897 Player.p_mana -= dtemp;
899 if (Curmonster.m_type == SM_DARKLORD)
900 /* magic bolts don't work against D. L. */
903 inflict = dtemp * ROLL(15.0, sqrt(Player.p_magiclvl / 3.0 + 1.0));
904 mvaddstr(5, 0, "Magic Bolt fired!\n");
909 case '3': /* force field */
910 if (Player.p_magiclvl < ML_FORCEFIELD)
912 else if (Player.p_mana < MM_FORCEFIELD)
916 Player.p_mana -= MM_FORCEFIELD;
917 Shield = (Player.p_maxenergy + Player.p_shield) * 4.2 + 45.0;
918 mvaddstr(5, 0, "Force Field up.\n");
922 case '4': /* transform */
923 if (Player.p_magiclvl < ML_XFORM)
925 else if (Player.p_mana < MM_XFORM)
929 Player.p_mana -= MM_XFORM;
930 Whichmonster = (int) ROLL(0.0, 100.0);
931 longjmp(Fightenv, 0);
936 case '5': /* increase might */
937 if (Player.p_magiclvl < ML_INCRMIGHT)
939 else if (Player.p_mana < MM_INCRMIGHT)
943 Player.p_mana -= MM_INCRMIGHT;
945 (1.2 * (Player.p_strength + Player.p_sword)
946 + 5.0 - Player.p_might) / 2.0;
947 mvprintw(5, 0, "New strength: %.0f\n", Player.p_might);
951 case '6': /* invisible */
952 if (Player.p_magiclvl < ML_INVISIBLE)
954 else if (Player.p_mana < MM_INVISIBLE)
958 Player.p_mana -= MM_INVISIBLE;
960 (1.2 * (Player.p_quickness + Player.p_quksilver)
961 + 5.0 - Player.p_speed) / 2.0;
962 mvprintw(5, 0, "New quickness: %.0f\n", Player.p_speed);
966 case '7': /* transport */
967 if (Player.p_magiclvl < ML_XPORT)
969 else if (Player.p_mana < MM_XPORT)
973 Player.p_mana -= MM_XPORT;
974 if (Player.p_brains + Player.p_magiclvl
975 < Curmonster.m_experience / 200.0 * drandom())
977 mvaddstr(5, 0, "Transport backfired!\n");
978 altercoordinates(0.0, 0.0, A_FAR);
983 mvprintw(5, 0, "%s is transported.\n", Enemyname);
985 /* monster didn't drop its treasure */
986 Curmonster.m_treasuretype = 0;
988 Curmonster.m_energy = 0.0;
993 case '8': /* paralyze */
994 if (Player.p_magiclvl < ML_PARALYZE)
996 else if (Player.p_mana < MM_PARALYZE)
1000 Player.p_mana -= MM_PARALYZE;
1001 if (Player.p_magiclvl >
1002 Curmonster.m_experience / 1000.0 * drandom())
1004 mvprintw(5, 0, "%s is held.\n", Enemyname);
1005 Curmonster.m_speed = -2.0;
1008 mvaddstr(5, 0, "Monster unaffected.\n");
1012 case '9': /* specify */
1013 if (Player.p_specialtype < SC_COUNCIL)
1015 else if (Player.p_mana < MM_SPECIFY)
1019 Player.p_mana -= MM_SPECIFY;
1020 mvaddstr(5, 0, "Which monster do you want [0-99] ? ");
1021 Whichmonster = (int) infloat();
1022 Whichmonster = MAX(0, MIN(99, Whichmonster));
1023 longjmp(Fightenv, 0);
1030 /************************************************************************
1032 / FUNCTION NAME: callmonster()
1034 / FUNCTION: read monster from file, and fill structure
1036 / AUTHOR: E. A. Estes, 2/25/86
1039 / int which - which monster to call
1041 / RETURN VALUE: none
1043 / MODULES CALLED: truncstring(), fread(), fseek(), floor(), drandom(),
1046 / GLOBAL INPUTS: Curmonster, Circle, Player, *Monstfp
1048 / GLOBAL OUTPUTS: Curmonster, Player, *Enemyname
1051 / Read specified monster from monster database and fill up
1052 / current monster structure.
1053 / Adjust statistics based upon current size.
1054 / Handle some special monsters.
1056 *************************************************************************/
1061 struct monster Othermonster; /* to find a name for mimics */
1063 which = MIN(which, 99); /* make sure within range */
1065 /* fill structure */
1066 fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0);
1067 fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
1069 /* handle some special monsters */
1070 if (Curmonster.m_type == SM_MODNAR)
1072 if (Player.p_specialtype < SC_COUNCIL)
1073 /* randomize some stats */
1075 Curmonster.m_strength *= drandom() + 0.5;
1076 Curmonster.m_brains *= drandom() + 0.5;
1077 Curmonster.m_speed *= drandom() + 0.5;
1078 Curmonster.m_energy *= drandom() + 0.5;
1079 Curmonster.m_experience *= drandom() + 0.5;
1080 Curmonster.m_treasuretype =
1081 (int) ROLL(0.0, (double) Curmonster.m_treasuretype);
1084 /* make Modnar into Morgoth */
1086 strcpy(Curmonster.m_name, "Morgoth");
1087 Curmonster.m_strength = drandom() * (Player.p_maxenergy + Player.p_shield) / 1.4
1088 + drandom() * (Player.p_maxenergy + Player.p_shield) / 1.5;
1089 Curmonster.m_brains = Player.p_brains;
1090 Curmonster.m_energy = Player.p_might * 30.0;
1091 Curmonster.m_type = SM_MORGOTH;
1092 Curmonster.m_speed = Player.p_speed * 1.1
1093 + (Player.p_specialtype == SC_EXVALAR) ? Player.p_speed : 0.0;
1094 Curmonster.m_flock = 0.0;
1095 Curmonster.m_treasuretype = 0;
1096 Curmonster.m_experience = 0.0;
1099 else if (Curmonster.m_type == SM_MIMIC)
1100 /* pick another name */
1102 which = (int) ROLL(0.0, 100.0);
1103 fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0);
1104 fread(&Othermonster, SZ_MONSTERSTRUCT, 1, Monstfp);
1105 strcpy(Curmonster.m_name, Othermonster.m_name);
1108 truncstring(Curmonster.m_name);
1110 if (Curmonster.m_type != SM_MORGOTH)
1111 /* adjust stats based on which circle player is in */
1113 Curmonster.m_strength *= (1.0 + Circle / 2.0);
1114 Curmonster.m_brains *= Circle;
1115 Curmonster.m_speed += Circle * 1.e-9;
1116 Curmonster.m_energy *= Circle;
1117 Curmonster.m_experience *= Circle;
1120 if (Player.p_blindness)
1121 /* cannot see monster if blind */
1122 Enemyname = "A monster";
1124 Enemyname = Curmonster.m_name;
1126 if (Player.p_speed <= 0.0)
1127 /* make Player.p_speed positive */
1129 Curmonster.m_speed += -Player.p_speed;
1130 Player.p_speed = 1.0;
1133 /* fill up the rest of the structure */
1134 Curmonster.m_o_strength = Curmonster.m_strength;
1135 Curmonster.m_o_speed = Curmonster.m_maxspeed = Curmonster.m_speed;
1136 Curmonster.m_o_energy = Curmonster.m_energy;
1137 Curmonster.m_melee = Curmonster.m_skirmish = 0.0;
1140 /************************************************************************
1142 / FUNCTION NAME: awardtreasure()
1144 / FUNCTION: select a treasure
1146 / AUTHOR: E. A. Estes, 12/4/85
1150 / RETURN VALUE: none
1152 / MODULES CALLED: pickmonster(), collecttaxes(), more(), cursedtreasure(),
1153 / floor(), wmove(), drandom(), sscanf(), printw(), altercoordinates(),
1154 / longjmp(), infloat(), waddstr(), getanswer(), getstring(), wclrtobot()
1156 / GLOBAL INPUTS: Somebetter[], Curmonster, Whichmonster, Circle, Player,
1157 / *stdscr, Databuf[], *Statptr, Fightenv[]
1159 / GLOBAL OUTPUTS: Whichmonster, Shield, Player
1162 / Roll up a treasure based upon monster type and size, and
1163 / certain player statistics.
1164 / Handle cursed treasure.
1166 *************************************************************************/
1170 int whichtreasure; /* calculated treasure to grant */
1171 int temp; /* temporary */
1173 double treasuretype; /* monster's treasure type */
1174 double gold = 0.0; /* gold awarded */
1175 double gems = 0.0; /* gems awarded */
1176 double dtemp; /* for temporary calculations */
1178 whichtreasure = (int) ROLL(1.0, 3.0); /* pick a treasure */
1179 treasuretype = (double) Curmonster.m_treasuretype;
1185 if (drandom() > 0.65)
1188 if (Curmonster.m_treasuretype > 7)
1191 gems = ROLL(1.0, (treasuretype - 7.0)
1192 * (treasuretype - 7.0) * (Circle - 1.0) / 4.0);
1193 printw("You have discovered %.0f gems!", gems);
1198 gold = ROLL(treasuretype * 10.0, treasuretype
1199 * treasuretype * 10.0 * (Circle - 1.0));
1200 printw("You have found %.0f gold pieces.", gold);
1203 addstr(" Do you want to pick them up ? ");
1204 ch = getanswer("NY", FALSE);
1208 if (drandom() < treasuretype / 35.0 + 0.04)
1211 addstr("They were cursed!\n");
1215 collecttaxes(gold, gems);
1221 /* other treasures */
1223 addstr("You have found some treasure. Do you want to inspect it ? ");
1224 ch = getanswer("NY", FALSE);
1230 if (drandom() < 0.08 && Curmonster.m_treasuretype != 4)
1232 addstr("It was cursed!\n");
1237 switch (Curmonster.m_treasuretype)
1239 case 1: /* treasure type 1 */
1240 switch (whichtreasure)
1243 addstr("You've discovered a power booster!\n");
1244 Player.p_mana += ROLL(Circle * 4.0, Circle * 30.0);
1248 addstr("You have encountered a druid.\n");
1249 Player.p_experience +=
1250 ROLL(0.0, 2000.0 + Circle * 400.0);
1254 addstr("You have found a holy orb.\n");
1255 Player.p_sin = MAX(0.0, Player.p_sin - 0.25);
1259 /* end treasure type 1 */
1261 case 2: /* treasure type 2 */
1262 switch (whichtreasure)
1265 addstr("You have found an amulet.\n");
1270 addstr("You've found some holy water!\n");
1271 ++Player.p_holywater;
1275 addstr("You've met a hermit!\n");
1276 Player.p_sin *= 0.75;
1277 Player.p_mana += 12.0 * Circle;
1281 /* end treasure type 2 */
1283 case 3: /* treasure type 3 */
1284 switch (whichtreasure)
1287 dtemp = ROLL(7.0, 30.0 + Circle / 10.0);
1288 printw("You've found a +%.0f shield!\n", dtemp);
1289 if (dtemp >= Player.p_shield)
1290 Player.p_shield = dtemp;
1296 addstr("You have rescued a virgin. Will you be honorable ? ");
1297 ch = getanswer("NY", FALSE);
1300 Player.p_virgin = TRUE;
1303 Player.p_experience += 2000.0 * Circle;
1309 addstr("You've discovered some athelas!\n");
1314 /* end treasure type 3 */
1316 case 4: /* treasure type 4 */
1317 addstr("You've found a scroll. Will you read it ? ");
1318 ch = getanswer("NY", FALSE);
1322 switch ((int) ROLL(1, 6))
1325 addstr("It throws up a shield for you next monster.\n");
1326 getyx(stdscr, whichtreasure, ch);
1327 more(whichtreasure);
1329 (Player.p_maxenergy + Player.p_energy) * 5.5 + Circle * 50.0;
1330 Whichmonster = pickmonster();
1331 longjmp(Fightenv, 0);
1335 addstr("It makes you invisible for you next monster.\n");
1336 getyx(stdscr, whichtreasure, ch);
1337 more(whichtreasure);
1338 Player.p_speed = 1e6;
1339 Whichmonster = pickmonster();
1340 longjmp(Fightenv, 0);
1344 addstr("It increases your strength ten fold to fight your next monster.\n");
1345 getyx(stdscr, whichtreasure, ch);
1346 more(whichtreasure);
1347 Player.p_might *= 10.0;
1348 Whichmonster = pickmonster();
1349 longjmp(Fightenv, 0);
1353 addstr("It is a general knowledge scroll.\n");
1354 Player.p_brains += ROLL(2.0, Circle);
1355 Player.p_magiclvl += ROLL(1.0, Circle / 2.0);
1359 addstr("It tells you how to pick your next monster.\n");
1360 addstr("Which monster do you want [0-99] ? ");
1361 Whichmonster = (int) infloat();
1362 Whichmonster = MIN(99, MAX(0, Whichmonster));
1363 longjmp(Fightenv, 0);
1366 addstr("It was cursed!\n");
1371 /* end treasure type 4 */
1373 case 5: /* treasure type 5 */
1374 switch (whichtreasure)
1377 dtemp = ROLL(Circle / 4.0 + 5.0, Circle / 2.0 + 9.0);
1378 printw("You've discovered a +%.0f dagger.\n", dtemp);
1379 if (dtemp >= Player.p_sword)
1380 Player.p_sword = dtemp;
1386 dtemp = ROLL(7.5 + Circle * 3.0, Circle * 2.0 + 160.0);
1387 printw("You have found some +%.0f armour!\n", dtemp);
1388 if (dtemp >= Player.p_shield)
1389 Player.p_shield = dtemp;
1395 addstr("You've found a tablet.\n");
1396 Player.p_brains += 4.5 * Circle;
1400 /* end treasure type 5 */
1402 case 6: /* treasure type 6 */
1403 switch (whichtreasure)
1406 addstr("You've found a priest.\n");
1407 Player.p_energy = Player.p_maxenergy + Player.p_shield;
1408 Player.p_sin /= 2.0;
1409 Player.p_mana += 24.0 * Circle;
1410 Player.p_brains += Circle;
1414 addstr("You have come upon Robin Hood!\n");
1415 Player.p_shield += Circle * 2.0;
1416 Player.p_strength += Circle / 2.5 + 1.0;
1420 dtemp = ROLL(2.0 + Circle / 4.0, Circle / 1.2 + 10.0);
1421 printw("You have found a +%.0f axe!\n", dtemp);
1422 if (dtemp >= Player.p_sword)
1423 Player.p_sword = dtemp;
1429 /* end treasure type 6 */
1431 case 7: /* treasure type 7 */
1432 switch (whichtreasure)
1435 addstr("You've discovered a charm!\n");
1440 addstr("You have encountered Merlyn!\n");
1441 Player.p_brains += Circle + 5.0;
1442 Player.p_magiclvl += Circle / 3.0 + 5.0;
1443 Player.p_mana += Circle * 10.0;
1447 dtemp = ROLL(5.0 + Circle / 3.0, Circle / 1.5 + 20.0);
1448 printw("You have found a +%.0f war hammer!\n", dtemp);
1449 if (dtemp >= Player.p_sword)
1450 Player.p_sword = dtemp;
1456 /* end treasure type 7 */
1458 case 8: /* treasure type 8 */
1459 switch (whichtreasure)
1462 addstr("You have found a healing potion.\n");
1463 Player.p_poison = MIN(-2.0, Player.p_poison - 2.0);
1467 addstr("You have discovered a transporter. Do you wish to go anywhere ? ");
1468 ch = getanswer("NY", FALSE);
1474 addstr("X Y Coordinates ? ");
1475 getstring(Databuf, SZ_DATABUF);
1476 sscanf(Databuf, "%lf %lf", &x, &y);
1477 altercoordinates(x, y, A_FORCED);
1482 dtemp = ROLL(10.0 + Circle / 1.2, Circle * 3.0 + 30.0);
1483 printw("You've found a +%.0f sword!\n", dtemp);
1484 if (dtemp >= Player.p_sword)
1485 Player.p_sword = dtemp;
1491 /* end treasure type 8 */
1496 case 13: /* treasure types 10 - 13 */
1497 if (drandom() < 0.33)
1499 if (Curmonster.m_treasuretype == 10)
1501 addstr("You've found a pair of elven boots!\n");
1502 Player.p_quickness += 2.0;
1505 else if (Curmonster.m_treasuretype == 11
1506 && !Player.p_palantir)
1508 addstr("You've acquired Saruman's palantir.\n");
1509 Player.p_palantir = TRUE;
1512 else if (Player.p_ring.ring_type == R_NONE
1513 && Player.p_specialtype < SC_COUNCIL
1514 && (Curmonster.m_treasuretype == 12
1515 || Curmonster.m_treasuretype == 13))
1516 /* roll up a ring */
1518 if (drandom() < 0.8)
1521 if (Curmonster.m_treasuretype == 12)
1523 whichtreasure = R_NAZREG;
1528 whichtreasure = R_DLREG;
1535 whichtreasure = R_BAD;
1536 temp = 15 + Statptr->c_ringduration + (int) ROLL(0,5);
1539 addstr("You've discovered a ring. Will you pick it up ? ");
1540 ch = getanswer("NY", FALSE);
1545 Player.p_ring.ring_type = whichtreasure;
1546 Player.p_ring.ring_duration = temp;
1552 /* end treasure types 10 - 13 */
1553 /* fall through to treasure type 9 if no treasure from above */
1555 case 9: /* treasure type 9 */
1556 switch (whichtreasure)
1559 if (Player.p_level <= 1000.0
1560 && Player.p_crowns <= 3
1561 && Player.p_level >= 10.0)
1563 addstr("You have found a golden crown!\n");
1567 /* fall through otherwise */
1570 addstr("You've been blessed!\n");
1571 Player.p_blessing = TRUE;
1572 Player.p_sin /= 3.0;
1573 Player.p_energy = Player.p_maxenergy + Player.p_shield;
1574 Player.p_mana += 100.0 * Circle;
1578 dtemp = ROLL(1.0, Circle / 5.0 + 5.0);
1579 dtemp = MIN(dtemp, 99.0);
1580 printw("You have discovered some +%.0f quicksilver!\n",dtemp);
1581 if (dtemp >= Player.p_quksilver)
1582 Player.p_quksilver = dtemp;
1588 /* end treasure type 9 */
1593 /************************************************************************
1595 / FUNCTION NAME: cursedtreasure()
1597 / FUNCTION: take care of cursed treasure
1599 / AUTHOR: E. A. Estes, 12/4/85
1603 / RETURN VALUE: none
1605 / MODULES CALLED: waddstr()
1607 / GLOBAL INPUTS: Player, *stdscr
1609 / GLOBAL OUTPUTS: Player
1612 / Handle cursed treasure. Look for amulets and charms to save
1613 / the player from the curse.
1615 *************************************************************************/
1619 if (Player.p_charms > 0)
1621 addstr("But your charm saved you!\n");
1624 else if (Player.p_amulets > 0)
1626 addstr("But your amulet saved you!\n");
1631 Player.p_energy = (Player.p_maxenergy + Player.p_shield) / 10.0;
1632 Player.p_poison += 0.25;
1636 /************************************************************************
1638 / FUNCTION NAME: scramblestats()
1640 / FUNCTION: scramble some selected statistics
1642 / AUTHOR: E. A. Estes, 12/4/85
1646 / RETURN VALUE: none
1648 / MODULES CALLED: floor(), drandom()
1650 / GLOBAL INPUTS: Player
1652 / GLOBAL OUTPUTS: Player
1655 / Swap a few player statistics randomly.
1657 *************************************************************************/
1661 double dbuf[6]; /* to put statistic in */
1662 double dtemp1, dtemp2; /* for swapping values */
1663 int first, second; /* indices for swapping */
1664 double *dptr; /* pointer for filling and emptying buf[] */
1668 *dptr++ = Player.p_strength;
1669 *dptr++ = Player.p_mana;
1670 *dptr++ = Player.p_brains;
1671 *dptr++ = Player.p_magiclvl;
1672 *dptr++ = Player.p_energy;
1673 *dptr = Player.p_sin;
1675 /* pick values to swap */
1676 first = (int) ROLL(0, 5);
1677 second = (int) ROLL(0, 5);
1681 dtemp1 = dptr[first];
1682 /* this expression is split to prevent a compiler loop on some compilers */
1683 dtemp2 = dptr[second];
1684 dptr[first] = dtemp2;
1685 dptr[second] = dtemp1;
1688 Player.p_strength = *dptr++;
1689 Player.p_mana = *dptr++;
1690 Player.p_brains = *dptr++;
1691 Player.p_magiclvl = *dptr++;
1692 Player.p_energy = *dptr++;
1693 Player.p_sin = *dptr;