comparison rogue4/fight.c @ 12:9535a08ddc39

Import Rogue 5.2 from the Roguelike Restoration Project (r1490)
author edwarj4
date Sat, 24 Oct 2009 16:52:52 +0000
parents
children 1b73a8641b37
comparison
equal deleted inserted replaced
11:949d558c2162 12:9535a08ddc39
1 /*
2 * All the fighting gets done here
3 *
4 * @(#)fight.c 4.30 (Berkeley) 4/6/82
5 *
6 * Rogue: Exploring the Dungeons of Doom
7 * Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
8 * All rights reserved.
9 *
10 * See the file LICENSE.TXT for full copyright and licensing information.
11 */
12
13 #include <curses.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include "rogue.h"
17
18 long e_levels[] = {
19 10L,20L,40L,80L,160L,320L,640L,1280L,2560L,5120L,10240L,20480L,
20 40920L, 81920L, 163840L, 327680L, 655360L, 1310720L, 2621440L, 0L
21 };
22
23 /*
24 * fight:
25 * The player attacks the monster.
26 */
27 fight(mp, mn, weap, thrown)
28 register coord *mp;
29 char mn;
30 register THING *weap;
31 bool thrown;
32 {
33 register THING *tp;
34 register bool did_hit = TRUE;
35 register const char *mname;
36
37 /*
38 * Find the monster we want to fight
39 */
40 #ifdef WIZARD
41 if ((tp = moat(mp->y, mp->x)) == NULL)
42 debug("Fight what @ %d,%d", mp->y, mp->x);
43 #else
44 tp = moat(mp->y, mp->x);
45 #endif
46 /*
47 * Since we are fighting, things are not quiet so no healing takes
48 * place.
49 */
50 count = quiet = 0;
51 runto(mp, &hero);
52 /*
53 * Let him know it was really a mimic (if it was one).
54 */
55 if (tp->t_type == 'M' && tp->t_disguise != 'M' && !on(player, ISBLIND))
56 {
57 tp->t_disguise = 'M';
58 if (!thrown)
59 return FALSE;
60 msg("wait! That's a mimic!");
61 }
62 did_hit = FALSE;
63 if (on(player, ISBLIND))
64 mname = "it";
65 else
66 mname = monsters[mn-'A'].m_name;
67 if (roll_em(&player, tp, weap, thrown))
68 {
69 did_hit = FALSE;
70 if (thrown)
71 thunk(weap, mname);
72 else
73 hit(NULL, mname);
74 if (on(player, CANHUH))
75 {
76 did_hit = TRUE;
77 tp->t_flags |= ISHUH;
78 player.t_flags &= ~CANHUH;
79 msg("your hands stop glowing red");
80 }
81 if (tp->t_stats.s_hpt <= 0)
82 killed(tp, TRUE);
83 else if (did_hit && !on(player, ISBLIND))
84 msg("the %s appears confused", mname);
85 did_hit = TRUE;
86 }
87 else
88 if (thrown)
89 bounce(weap, mname);
90 else
91 miss(NULL, mname);
92 return did_hit;
93 }
94
95 /*
96 * attack:
97 * The monster attacks the player
98 */
99 attack(mp)
100 register THING *mp;
101 {
102 register const char *mname;
103
104 /*
105 * Since this is an attack, stop running and any healing that was
106 * going on at the time.
107 */
108 running = FALSE;
109 count = quiet = 0;
110 if (mp->t_type == 'M' && !on(player, ISBLIND))
111 mp->t_disguise = 'M';
112 if (on(player, ISBLIND))
113 mname = "it";
114 else
115 mname = monsters[mp->t_type-'A'].m_name;
116 if (roll_em(mp, &player, NULL, FALSE))
117 {
118 if (mp->t_type != 'E')
119 hit(mname, NULL);
120 if (pstats.s_hpt <= 0)
121 death(mp->t_type); /* Bye bye life ... */
122 if (!on(*mp, ISCANC))
123 switch (mp->t_type)
124 {
125 case 'R':
126 /*
127 * If a rust monster hits, you lose armor, unless
128 * that armor is leather or there is a magic ring
129 */
130 if (cur_armor != NULL && cur_armor->o_ac < 9
131 && cur_armor->o_which != LEATHER)
132 if (ISWEARING(R_SUSTARM))
133 msg("The rust vanishes instantly");
134 else
135 {
136 cur_armor->o_ac++;
137 if (!terse)
138 msg("your armor appears to be weaker now. Oh my!");
139 else
140 msg("your armor weakens");
141 }
142 when 'E':
143 /*
144 * The gaze of the floating eye hypnotizes you
145 */
146 if (on(player, ISBLIND))
147 break;
148 player.t_flags &= ~ISRUN;
149 if (!no_command)
150 {
151 addmsg("you are transfixed");
152 if (!terse)
153 addmsg(" by the gaze of the floating eye");
154 endmsg();
155 }
156 no_command += rnd(2) + 2;
157 when 'A':
158 /*
159 * Ants have poisonous bites
160 */
161 if (!save(VS_POISON))
162 if (!ISWEARING(R_SUSTSTR))
163 {
164 chg_str(-1);
165 if (!terse)
166 msg("you feel a sting in your arm and now feel weaker");
167 else
168 msg("a sting has weakened you");
169 }
170 else
171 if (!terse)
172 msg("a sting momentarily weakens you");
173 else
174 msg("sting has no effect");
175 when 'W':
176 case 'V':
177 /*
178 * Wraiths might drain energy levels, and Vampires
179 * can steal max_hp
180 */
181 if (rnd(100) < (mp->t_type == 'W' ? 15 : 30))
182 {
183 register int fewer;
184
185 if (mp->t_type == 'W')
186 {
187 if (pstats.s_exp == 0)
188 death('W'); /* All levels gone */
189 if (--pstats.s_lvl == 0)
190 {
191 pstats.s_exp = 0;
192 pstats.s_lvl = 1;
193 }
194 else
195 pstats.s_exp = e_levels[pstats.s_lvl-1]+1;
196 fewer = roll(1, 10);
197 }
198 else
199 fewer = roll(1, 5);
200 pstats.s_hpt -= fewer;
201 max_hp -= fewer;
202 if (pstats.s_hpt < 1)
203 pstats.s_hpt = 1;
204 if (max_hp < 1)
205 death(mp->t_type);
206 msg("you suddenly feel weaker");
207 }
208 when 'F':
209 /*
210 * Violet fungi stops the poor guy from moving
211 */
212 player.t_flags |= ISHELD;
213 sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dd1",++fung_hit);
214 when 'L':
215 {
216 /*
217 * Leperachaun steals some gold
218 */
219 register long lastpurse;
220
221 lastpurse = purse;
222 purse -= GOLDCALC;
223 if (!save(VS_MAGIC))
224 purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
225 if (purse < 0)
226 purse = 0;
227 remove_monster(&mp->t_pos, mp, FALSE);
228 mp = NULL;
229 if (purse != lastpurse)
230 msg("your purse feels lighter");
231 }
232 when 'N':
233 {
234 register THING *obj, *steal;
235 register int nobj;
236
237 /*
238 * Nymph's steal a magic item, look through the pack
239 * and pick out one we like.
240 */
241 steal = NULL;
242 for (nobj = 0, obj = pack; obj != NULL; obj = next(obj))
243 if (obj != cur_armor && obj != cur_weapon
244 && obj != cur_ring[LEFT] && obj != cur_ring[RIGHT]
245 && is_magic(obj) && rnd(++nobj) == 0)
246 steal = obj;
247 if (steal != NULL)
248 {
249 remove_monster(&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE);
250 mp = NULL;
251 inpack--;
252 if (steal->o_count > 1 && steal->o_group == 0)
253 {
254 register int oc;
255
256 oc = steal->o_count--;
257 steal->o_count = 1;
258 msg("she stole %s!", inv_name(steal, TRUE));
259 steal->o_count = oc;
260 }
261 else
262 {
263 detach(pack, steal);
264 msg("she stole %s!", inv_name(steal, TRUE));
265 discard(steal);
266 }
267 }
268 }
269 otherwise:
270 break;
271 }
272 }
273 else if (mp->t_type != 'E')
274 {
275 if (mp->t_type == 'F')
276 {
277 pstats.s_hpt -= fung_hit;
278 if (pstats.s_hpt <= 0)
279 death(mp->t_type); /* Bye bye life ... */
280 }
281 miss(mname, NULL);
282 }
283 if (fight_flush)
284 flush_type();
285 count = 0;
286 status();
287
288 if (mp == NULL)
289 return(-1);
290 else
291 return(0);
292 }
293
294 /*
295 * swing:
296 * Returns true if the swing hits
297 */
298 swing(at_lvl, op_arm, wplus)
299 int at_lvl, op_arm, wplus;
300 {
301 register int res = rnd(20);
302 register int need = (20 - at_lvl) - op_arm;
303
304 return (res + wplus >= need);
305 }
306
307 /*
308 * check_level:
309 * Check to see if the guy has gone up a level.
310 */
311 check_level()
312 {
313 register int i, add, olevel;
314
315 for (i = 0; e_levels[i] != 0; i++)
316 if (e_levels[i] > pstats.s_exp)
317 break;
318 i++;
319 olevel = pstats.s_lvl;
320 pstats.s_lvl = i;
321 if (i > olevel)
322 {
323 add = roll(i - olevel, 10);
324 max_hp += add;
325 if ((pstats.s_hpt += add) > max_hp)
326 pstats.s_hpt = max_hp;
327 msg("welcome to level %d", i);
328 }
329 }
330
331 /*
332 * roll_em:
333 * Roll several attacks
334 */
335 roll_em(thatt, thdef, weap, hurl)
336 THING *thatt, *thdef, *weap;
337 bool hurl;
338 {
339 register struct stats *att, *def;
340 register char *cp;
341 register int ndice, nsides, def_arm;
342 register bool did_hit = FALSE;
343 register int hplus;
344 register int dplus;
345 register int damage;
346
347 att = &thatt->t_stats;
348 def = &thdef->t_stats;
349 if (weap == NULL)
350 {
351 cp = att->s_dmg;
352 dplus = 0;
353 hplus = 0;
354 }
355 else
356 {
357 hplus = (weap == NULL ? 0 : weap->o_hplus);
358 dplus = (weap == NULL ? 0 : weap->o_dplus);
359 if (weap == cur_weapon)
360 {
361 if (ISRING(LEFT, R_ADDDAM))
362 dplus += cur_ring[LEFT]->o_ac;
363 else if (ISRING(LEFT, R_ADDHIT))
364 hplus += cur_ring[LEFT]->o_ac;
365 if (ISRING(RIGHT, R_ADDDAM))
366 dplus += cur_ring[RIGHT]->o_ac;
367 else if (ISRING(RIGHT, R_ADDHIT))
368 hplus += cur_ring[RIGHT]->o_ac;
369 }
370 if (hurl)
371 if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&
372 cur_weapon->o_which == weap->o_launch)
373 {
374 cp = weap->o_hurldmg;
375 hplus += cur_weapon->o_hplus;
376 dplus += cur_weapon->o_dplus;
377 }
378 else
379 cp = weap->o_hurldmg;
380 else
381 {
382 cp = weap->o_damage;
383 /*
384 * Drain a staff of striking
385 */
386 if (weap->o_type == STICK && weap->o_which == WS_HIT
387 && --weap->o_charges < 0)
388 {
389 strcpy(weap->o_damage,"0d0");
390 cp = weap->o_damage;
391 weap->o_hplus = weap->o_dplus = 0;
392 weap->o_charges = 0;
393 }
394 }
395 }
396 /*
397 * If the creature being attacked is not running (alseep or held)
398 * then the attacker gets a plus four bonus to hit.
399 */
400 if (!on(*thdef, ISRUN))
401 hplus += 4;
402 def_arm = def->s_arm;
403 if (def == &pstats)
404 {
405 if (cur_armor != NULL)
406 def_arm = cur_armor->o_ac;
407 if (ISRING(LEFT, R_PROTECT))
408 def_arm -= cur_ring[LEFT]->o_ac;
409 if (ISRING(RIGHT, R_PROTECT))
410 def_arm -= cur_ring[RIGHT]->o_ac;
411 }
412 for (;;)
413 {
414 ndice = atoi(cp);
415 if ((cp = strchr(cp, 'd')) == NULL)
416 break;
417 nsides = atoi(++cp);
418 if (swing(att->s_lvl, def_arm, hplus + str_plus(att->s_str)))
419 {
420 register int proll;
421
422 proll = roll(ndice, nsides);
423 #ifdef WIZARD
424 if (ndice + nsides > 0 && proll < 1)
425 debug("Damage for %dd%d came out %d, dplus = %d, add_dam = %d, def_arm = %d", ndice, nsides, proll, dplus, add_dam(att->s_str), def_arm);
426 #endif
427 damage = dplus + proll + add_dam(att->s_str);
428 def->s_hpt -= max(0, damage);
429 did_hit = TRUE;
430 }
431 if ((cp = strchr(cp, '/')) == NULL)
432 break;
433 cp++;
434 }
435 return did_hit;
436 }
437
438 /*
439 * prname:
440 * The print name of a combatant
441 */
442 char *
443 prname(who, upper)
444 register char *who;
445 bool upper;
446 {
447 static char tbuf[MAXSTR];
448
449 *tbuf = '\0';
450 if (who == 0)
451 strcpy(tbuf, "you");
452 else if (on(player, ISBLIND))
453 strcpy(tbuf, "it");
454 else
455 {
456 strcpy(tbuf, "the ");
457 strcat(tbuf, who);
458 }
459 if (upper)
460 *tbuf = toupper(*tbuf);
461 return tbuf;
462 }
463
464 /*
465 * hit:
466 * Print a message to indicate a succesful hit
467 */
468 hit(er, ee)
469 register char *er, *ee;
470 {
471 register char *s = "";
472
473 addmsg(prname(er, TRUE));
474 if (terse)
475 s = " hit";
476 else
477 switch (rnd(4))
478 {
479 case 0: s = " scored an excellent hit on ";
480 when 1: s = " hit ";
481 when 2: s = (er == 0 ? " have injured " : " has injured ");
482 when 3: s = (er == 0 ? " swing and hit " : " swings and hits ");
483 }
484 addmsg(s);
485 if (!terse)
486 addmsg(prname(ee, FALSE));
487 endmsg();
488 }
489
490 /*
491 * miss:
492 * Print a message to indicate a poor swing
493 */
494 miss(er, ee)
495 register char *er, *ee;
496 {
497 register char *s = "";
498
499 addmsg(prname(er, TRUE));
500 switch (terse ? 0 : rnd(4))
501 {
502 case 0: s = (er == 0 ? " miss" : " misses");
503 when 1: s = (er == 0 ? " swing and miss" : " swings and misses");
504 when 2: s = (er == 0 ? " barely miss" : " barely misses");
505 when 3: s = (er == 0 ? " don't hit" : " doesn't hit");
506 }
507 addmsg(s);
508 if (!terse)
509 addmsg(" %s", prname(ee, FALSE));
510 endmsg();
511 }
512
513 /*
514 * save_throw:
515 * See if a creature save against something
516 */
517 save_throw(which, tp)
518 int which;
519 THING *tp;
520 {
521 register int need;
522
523 need = 14 + which - tp->t_stats.s_lvl / 2;
524 return (roll(1, 20) >= need);
525 }
526
527 /*
528 * save:
529 * See if he saves against various nasty things
530 */
531 save(which)
532 register int which;
533 {
534 if (which == VS_MAGIC)
535 {
536 if (ISRING(LEFT, R_PROTECT))
537 which -= cur_ring[LEFT]->o_ac;
538 if (ISRING(RIGHT, R_PROTECT))
539 which -= cur_ring[RIGHT]->o_ac;
540 }
541 return save_throw(which, &player);
542 }
543
544 /*
545 * str_plus:
546 * Compute bonus/penalties for strength on the "to hit" roll
547 */
548 str_plus(str)
549 register str_t str;
550 {
551 if (str == 31)
552 return 3;
553 if (str > 20)
554 return 2;
555 if (str > 16)
556 return 1;
557 if (str > 6)
558 return 0;
559 return str - 7;
560 }
561
562 /*
563 * add_dam:
564 * Compute additional damage done for exceptionally high or low strength
565 */
566 add_dam(str)
567 register str_t str;
568 {
569 if (str == 31)
570 return 6;
571 if (str > 21)
572 return 5;
573 if (str == 21)
574 return 4;
575 if (str > 18)
576 return 3;
577 if (str == 18)
578 return 2;
579 if (str > 15)
580 return 1;
581 if (str > 6)
582 return 0;
583 return str - 7;
584 }
585
586 /*
587 * raise_level:
588 * The guy just magically went up a level.
589 */
590 raise_level()
591 {
592 pstats.s_exp = e_levels[pstats.s_lvl-1] + 1L;
593 check_level();
594 }
595
596 /*
597 * thunk:
598 * A missile hits a monster
599 */
600 thunk(weap, mname)
601 register THING *weap;
602 register const char *mname;
603 {
604 if (weap->o_type == WEAPON)
605 addmsg("the %s hits ", w_names[weap->o_which]);
606 else
607 addmsg("you hit ");
608 if (on(player, ISBLIND))
609 msg("it");
610 else
611 msg("the %s", mname);
612 }
613
614 /*
615 * bounce:
616 * A missile misses a monster
617 */
618 bounce(weap, mname)
619 register THING *weap;
620 register const char *mname;
621 {
622 if (weap->o_type == WEAPON)
623 addmsg("the %s misses ", w_names[weap->o_which]);
624 else
625 addmsg("you missed ");
626 if (on(player, ISBLIND))
627 msg("it");
628 else
629 msg("the %s", mname);
630 }
631
632 /*
633 * remove:
634 * Remove a monster from the screen
635 */
636 remove_monster(mp, tp, waskill)
637 register coord *mp;
638 register THING *tp;
639 bool waskill;
640 {
641 register THING *obj, *nexti;
642
643 for (obj = tp->t_pack; obj != NULL; obj = nexti)
644 {
645 nexti = next(obj);
646 obj->o_pos = tp->t_pos;
647 detach(tp->t_pack, obj);
648 if (waskill)
649 fall(obj, FALSE);
650 else
651 discard(obj);
652 }
653 moat(mp->y, mp->x) = NULL;
654 mvaddch(mp->y, mp->x, tp->t_oldch);
655 detach(mlist, tp);
656 discard(tp);
657 }
658
659 /*
660 * is_magic:
661 * Returns true if an object radiates magic
662 */
663 is_magic(obj)
664 register THING *obj;
665 {
666 switch (obj->o_type)
667 {
668 case ARMOR:
669 return obj->o_ac != a_class[obj->o_which];
670 case WEAPON:
671 return obj->o_hplus != 0 || obj->o_dplus != 0;
672 case POTION:
673 case SCROLL:
674 case STICK:
675 case RING:
676 case AMULET:
677 return TRUE;
678 }
679 return FALSE;
680 }
681
682 /*
683 * killed:
684 * Called to put a monster to death
685 */
686 killed(tp, pr)
687 register THING *tp;
688 bool pr;
689 {
690 pstats.s_exp += tp->t_stats.s_exp;
691 /*
692 * If the monster was a violet fungi, un-hold him
693 */
694 switch (tp->t_type)
695 {
696 case 'F':
697 player.t_flags &= ~ISHELD;
698 fung_hit = 0;
699 strcpy(monsters['F'-'A'].m_stats.s_dmg, "000d0");
700 when 'L':
701 {
702 register THING *gold;
703
704 if (fallpos(&tp->t_pos, &tp->t_room->r_gold, TRUE))
705 {
706 gold = new_item();
707 gold->o_type = GOLD;
708 gold->o_goldval = GOLDCALC;
709 if (save(VS_MAGIC))
710 gold->o_goldval += GOLDCALC + GOLDCALC
711 + GOLDCALC + GOLDCALC;
712 attach(tp->t_pack, gold);
713 }
714 }
715 }
716 /*
717 * Get rid of the monster.
718 */
719 if (pr)
720 {
721 if (!terse)
722 addmsg("you have ");
723 addmsg("defeated ");
724 if (on(player, ISBLIND))
725 msg("it");
726 else
727 {
728 if (!terse)
729 addmsg("the ");
730 msg("%s", monsters[tp->t_type-'A'].m_name);
731 }
732 }
733 remove_monster(&tp->t_pos, tp, TRUE);
734 /*
735 * Do adjustments if he went up a level
736 */
737 check_level();
738 }