comparison urogue/fight.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children 317166b49d8a
comparison
equal deleted inserted replaced
253:d9badb9c0179 256:c495a4f288c6
1 /*
2 fight.c - All the fighting gets done here
3
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom
5 Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
6 All rights reserved.
7
8 Based on "Advanced Rogue"
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
10 All rights reserved.
11
12 Based on "Rogue: Exploring the Dungeons of Doom"
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
14 All rights reserved.
15
16 See the file LICENSE.TXT for full copyright and licensing information.
17 */
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include "rogue.h"
23
24 /*
25 * This are the beginning experience levels for all players all further
26 * experience levels are computed by multiplying by 2
27 */
28
29 static long e_levels[10] =
30 {
31 143L, /* Fighter */
32 182L, /* Paladin */
33 169L, /* Ranger */
34 127L, /* Cleric */
35 154L, /* Druid */
36 185L, /* Magician */
37 169L, /* Illusionist */
38 112L, /* Thief */
39 126L, /* Assasin */
40 319L /* Ninja */
41 };
42
43 static struct matrix att_mat[11] =
44 {
45 /* Base, Max_lvl, Factor, Offset, Range */
46
47 { 10, 17, 2, 1, 2 }, /* fi */
48 { 10, 17, 2, 1, 2 }, /* pa */
49 { 10, 17, 2, 1, 2 }, /* ra */
50 { 10, 19, 2, 1, 3 }, /* cl */
51 { 10, 19, 2, 1, 3 }, /* dr */
52 { 9, 21, 2, 1, 5 }, /* mu */
53 { 9, 21, 2, 1, 5 }, /* il */
54 { 10, 21, 2, 1, 4 }, /* th */
55 { 10, 21, 2, 1, 4 }, /* as */
56 { 10, 21, 2, 1, 4 }, /* nj */
57 { 7, 25, 1, 0, 2 } /* mn */
58 };
59
60 void
61 do_fight(coord dir, int tothedeath)
62 {
63 int x,y;
64
65 x = dir.x;
66 y = dir.y;
67
68 if (!tothedeath && pstats.s_hpt < max_stats.s_hpt / 3)
69 {
70 msg("That's not wise.");
71
72 after = fighting = FALSE;
73 return;
74 }
75
76 if (isalpha(CCHAR(winat(hero.y + y, hero.x + x))))
77 {
78 after = fighting = TRUE;
79 do_move(y, x);
80 }
81 else
82 {
83 if (fighting == FALSE)
84 msg("Nothing there.");
85
86 after = fighting = FALSE;
87 }
88
89 return;
90 }
91
92 /*
93 fight()
94 The player attacks the monster.
95 */
96
97 int
98 fight(coord *mp, struct object *weap, int thrown)
99 {
100 struct thing *tp;
101 struct linked_list *item;
102 int did_hit = TRUE;
103 char *mname;
104
105 /* Find the monster we want to fight */
106
107 if ((item = find_mons(mp->y, mp->x)) == NULL)
108 {
109 debug("Fight what @ %d,%d", mp->y, mp->x);
110 return 0;
111 }
112
113 tp = THINGPTR(item);
114
115 mname = (on(player, ISBLIND)) ? "it" : monsters[tp->t_index].m_name;
116
117 /* Since we are fighting, things are not quiet so no healing takes place */
118
119 player.t_rest_hpt = player.t_rest_pow = 0;
120 tp->t_rest_hpt = tp->t_rest_pow = 0;
121
122 /* Let him know it was really a mimic (if it was one). */
123
124 if (off(player, ISBLIND))
125 {
126 if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise))
127 {
128 msg("Wait! That's a %s!", mname);
129 turn_off(*tp, ISDISGUISE);
130 did_hit = thrown;
131 }
132
133 if (on(*tp, CANSURPRISE))
134 {
135 turn_off(*tp, CANSURPRISE);
136 if ((player.t_ctype == C_RANGER && rnd(6) != 0) ||
137 (player.t_ctype == C_NINJA && rnd(pstats.s_lvl / 2)
138 != 0))
139 msg("You notice a %s trying to hide!", mname);
140 else
141 {
142 msg("Wait! There's a %s!", mname);
143 did_hit = thrown;
144 }
145 }
146 }
147
148 /* Protection from Normal Missiles */
149
150 if (thrown && on(*tp, HASMSHIELD))
151 {
152 msg("The %s slows as it approaches %s.",
153 weaps[weap->o_which].w_name, mname);
154
155 did_hit = FALSE;
156 }
157
158 if (did_hit)
159 {
160 did_hit = FALSE;
161
162 if (!can_blink(tp) &&
163 (off(*tp, MAGICHIT) || (weap != NULL &&
164 (weap->o_hplus > 0 || weap->o_dplus > 0))) &&
165 (off(*tp, BMAGICHIT) || (weap != NULL &&
166 (weap->o_hplus > 2 || weap->o_dplus > 2))) &&
167 roll_em(&player, tp, weap, thrown, cur_weapon))
168 {
169 did_hit = TRUE;
170 tp->t_wasshot = TRUE;
171
172 if (thrown)
173 {
174 if (weap != NULL && weap->o_type == WEAPON
175 && weap->o_which == GRENADE)
176 {
177 hearmsg("BOOOM!");
178 aggravate();
179 }
180
181 thunk(weap, mname);
182 }
183 else
184 hit(mname);
185
186 /* hitting a friendly monster is curtains */
187
188 if (on(*tp, ISFRIENDLY))
189 {
190 turn_off(*tp, ISFRIENDLY);
191 turn_on(*tp, ISMEAN);
192 }
193
194 /* Charmed monsters become uncharmed */
195
196 if (on(*tp, ISCHARMED))
197 {
198 turn_off(*tp, ISCHARMED);
199 turn_on(*tp, ISMEAN);
200 }
201
202 /*
203 * If the player hit a rust monster, he better have a
204 * + weapon
205 */
206
207 if (on(*tp, CANRUST))
208 {
209 if (!thrown && (weap != NULL) &&
210 (weap->o_flags & ISMETAL) &&
211 !(weap->o_flags & ISPROT) &&
212 !(weap->o_flags & ISSILVER) &&
213 (weap->o_hplus < 1) && (weap->o_dplus < 1))
214 {
215 if (rnd(100) < 50)
216 weap->o_hplus--;
217 else
218 weap->o_dplus--;
219
220 msg("Your %s weakens!", weaps[weap->o_which].w_name);
221 }
222 else if (!thrown && weap != NULL && (weap->o_flags & ISMETAL))
223 msg("The rust vanishes from your %s!",
224 weaps[weap->o_which].w_name);
225 }
226
227 /* flammable monsters die from burning weapons */
228
229 if (thrown && on(*tp, CANBBURN) &&
230 (weap->o_flags & CANBURN) &&
231 !save_throw(VS_WAND, tp))
232 {
233 msg("The %s vanishes in a ball of flame.",
234 monsters[tp->t_index].m_name);
235
236 tp->t_stats.s_hpt = 0;
237 }
238
239 /* spores explode and infest hero */
240
241 if (on(*tp, CANSPORE))
242 {
243 msg("The %s explodes in a cloud of dust.",
244 monsters[tp->t_index].m_name);
245
246 if (is_wearing(R_HEALTH) ||
247 player.t_ctype == C_PALADIN ||
248 (player.t_ctype == C_NINJA && pstats.s_lvl
249 > 6) ||
250 thrown && rnd(50) > 0 ||
251 rnd(20) > 0)
252 {
253 msg("The dust makes it hard to breath.");
254 }
255 else
256 {
257 msg("You have contracted a parasitic infestation!");
258
259 infest_dam++;
260 turn_on(player, HASINFEST);
261 }
262
263 tp->t_stats.s_hpt = 0;
264 }
265
266 /* fireproof monsters laugh at you when burning weapon hits */
267
268 if (thrown && on(*tp, NOFIRE) && (weap->o_flags & CANBURN))
269 msg("The %s laughs as the %s bounces.",
270 monsters[tp->t_index].m_name,
271 weaps[weap->o_which].w_name);
272
273 /* sharp weapons have no effect on NOSHARP monsters */
274
275 if (on(*tp, NOSHARP) && (weap != NULL) &&
276 (weap->o_flags & ISSHARP))
277 {
278 msg("The %s has no effect on the %s!",
279 weaps[weap->o_which].w_name,
280 monsters[tp->t_index].m_name);
281
282 fighting = FALSE;
283 }
284
285 /* metal weapons pass through NOMETAL monsters */
286
287 if (on(*tp, NOMETAL) && (weap != NULL) &&
288 (weap->o_flags & ISMETAL))
289 {
290 msg("The %s passes through the %s!",
291 weaps[weap->o_which].w_name,
292 monsters[tp->t_index].m_name);
293
294 fighting = FALSE;
295 }
296
297 /*
298 * If the player hit something that shrieks, wake the
299 * dungeon
300 */
301
302 if (on(*tp, CANSHRIEK))
303 {
304 turn_off(*tp, CANSHRIEK);
305
306 if (on(player, CANHEAR))
307 {
308 msg("You are stunned by the %s's shriek.", mname);
309 no_command += 4 + rnd(8);
310 }
311 else if (off(player, ISDEAF))
312 msg("The %s emits a piercing shriek.", mname);
313 else
314 msg("The %s seems to be trying to make some noise.", mname);
315
316 aggravate();
317
318 if (rnd(wizard ? 3 : 39) == 0 && cur_armor
319 != NULL
320 && cur_armor->o_which == CRYSTAL_ARMOR)
321 {
322 struct linked_list *itm;
323 struct object *obj;
324
325 for (itm = pack; itm != NULL; itm = next(itm))
326 {
327 obj = OBJPTR(itm);
328
329 if (obj == cur_armor)
330 break;
331 }
332
333 if (itm == NULL)
334 debug("Can't find crystalline armor being worn.");
335 else
336 {
337 msg("Your armor shatters from the shriek.");
338 cur_armor = NULL;
339 del_pack(itm);
340 }
341 }
342 }
343
344 /*
345 * If the player hit something that can surprise, it
346 * can't now
347 */
348
349 if (on(*tp, CANSURPRISE))
350 turn_off(*tp, CANSURPRISE);
351
352 /*
353 * If the player hit something that can summon, it
354 * will try to
355 */
356
357 summon_help(tp, NOFORCE);
358
359 /* Can the player confuse? */
360
361 if (on(player, CANHUH) && !thrown)
362 {
363 seemsg("Your hands stop glowing red!");
364 seemsg("The %s appears confused.", mname);
365 turn_on(*tp, ISHUH);
366 turn_off(player, CANHUH);
367 }
368
369 /* Merchants just disappear if hit */
370
371 /*
372 * increases prices and curses objects from now on
373 * though
374 */
375
376 if (on(*tp, CANSELL))
377 {
378 msg("The %s disappears with his wares with a BOOM and a flash.",
379 mname);
380 killed(NULL, item, NOMESSAGE, NOPOINTS);
381 aggravate();
382 luck++;
383 }
384 else if (tp->t_stats.s_hpt <= 0)
385 killed(&player, item, MESSAGE, POINTS);
386
387 /*
388 * If the monster is fairly intelligent and about to
389 * die, it may turn tail and run.
390 */
391
392 else if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt / 10)) &&
393 (rnd(25) < tp->t_stats.s_intel))
394 {
395 turn_on(*tp, ISFLEE);
396
397 /* If monster was suffocating, stop it */
398
399 if (on(*tp, DIDSUFFOCATE))
400 {
401 turn_off(*tp, DIDSUFFOCATE);
402 extinguish_fuse(FUSE_SUFFOCATE);
403 }
404
405 /* If monster held us, stop it */
406
407 if (on(*tp, DIDHOLD) && (--hold_count == 0))
408 turn_off(player, ISHELD);
409
410 turn_off(*tp, DIDHOLD);
411
412 if (on(*tp, CANTELEPORT))
413 {
414 int rm;
415
416 /*
417 * Erase the monster from the old
418 * position
419 */
420
421 if (isalpha(mvwinch(cw, tp->t_pos.y, tp->t_pos.x)))
422 mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
423
424 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' ');
425
426 /* Get a new position */
427
428 do
429 {
430 rm = rnd_room();
431 rnd_pos(&rooms[rm], &tp->t_pos);
432 }
433 while (winat(tp->t_pos.y, tp->t_pos.x) != FLOOR);
434
435 /* Put it there */
436
437 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
438 tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) );
439 seemsg("The %s seems to have disappeared!", mname);
440 }
441 }
442 }
443 else if (thrown)
444 bounce(weap, mname);
445 else
446 miss(mname);
447 }
448
449 if (curr_mons)
450 chase_it(mp,&player); /* after so that backstabbing can happen */
451
452 count = 0;
453
454 return(did_hit);
455 }
456
457 /*
458 attack()
459 The monster attacks the player
460 */
461
462 int
463 attack(struct thing *mp, struct object *weapon, int thrown)
464 {
465 char *mname;
466 int did_hit = FALSE;
467
468 /* If the monster is in a wall, it cannot attack */
469
470 if (on(*mp, ISINWALL))
471 return (FALSE);
472
473 /* If two monsters start to gang up on our hero, stop fight mode */
474
475 if (fighting)
476 {
477 if (beast == NULL)
478 beast = mp;
479 else if (beast != mp)
480 fighting = FALSE;
481 }
482
483 /*
484 Since this is an attack, stop running and any healing that was
485 going on at the time.
486 */
487
488 running = FALSE;
489 player.t_rest_hpt = player.t_rest_pow = 0;
490 mp->t_rest_hpt = mp->t_rest_pow = 0;
491
492 if (on(*mp, ISDISGUISE) && off(player, ISBLIND))
493 turn_off(*mp, ISDISGUISE);
494 mname = on(player, ISBLIND) ? "the monster" :
495 monsters[mp->t_index].m_name;
496
497 if (roll_em(mp, &player, weapon, thrown, wield_weap(weapon, mp)) &&
498 (!thrown || off(player, HASMSHIELD)))
499 {
500 did_hit = TRUE;
501
502 m_thunk(weapon, mname);
503
504 if (pstats.s_hpt <= 0)
505 {
506 death(mp->t_index); /* Bye bye life ... */
507 return TRUE;
508 }
509
510 /* surprising monsters appear after they shoot at you */
511
512 if (thrown && on(*mp, CANSURPRISE))
513 turn_off(*mp, CANSURPRISE);
514 else if (!thrown)
515 {
516
517 /*
518 If a vampire hits, it may take half your hit
519 points
520 */
521
522 if ( on(*mp, CANSUCK) && !save(VS_MAGIC) )
523 {
524 if (pstats.s_hpt == 1)
525 {
526 death(mp->t_index);
527 return TRUE;
528 }
529 else
530 {
531 pstats.s_hpt /= 2;
532 msg("You feel your life force being drawn from you.");
533 }
534 }
535
536 /*
537 strong monsters can shatter or gong crystalline
538 armor
539 */
540
541 if (cur_armor != NULL && cur_armor->o_which == CRYSTAL_ARMOR)
542 {
543 if (rnd(mp->t_stats.s_str + (cur_armor->o_ac / 2)) > 20)
544 {
545 struct linked_list *item;
546 struct object *obj;
547
548 for (item = pack; item != NULL; item = next(item))
549 {
550 obj = OBJPTR(item);
551
552 if (obj == cur_armor)
553 break;
554 }
555
556 if (item == NULL)
557 debug("Can't find crystalline armor being worn.");
558 else
559 {
560 msg("Your armor is shattered by the blow.");
561 cur_armor = NULL;
562 del_pack(item);
563 }
564 }
565 else if (rnd(mp->t_stats.s_str) > 15)
566 {
567 msg("Your armor rings from the blow.");
568 aggravate();
569 }
570 }
571
572 /* Stinking monsters reduce the player's strength */
573
574 if (on(*mp, CANSTINK))
575 {
576 turn_off(*mp, CANSTINK);
577
578 if (player.t_ctype != C_PALADIN
579 && !(player.t_ctype == C_NINJA && pstats.s_lvl > 12)
580 && !save(VS_POISON))
581 {
582 if (on(player, CANSCENT))
583 {
584 msg("You pass out from the stench of the %s.", mname);
585 no_command += 4 + rnd(8);
586 }
587 else if (off(player, ISUNSMELL))
588 msg("The stench of the %s sickens you.", mname);
589
590 if (on(player, HASSTINK))
591 lengthen_fuse(FUSE_UNSTINK, STINKTIME);
592 else
593 {
594 turn_on(player, HASSTINK);
595 light_fuse(FUSE_UNSTINK, 0, STINKTIME, AFTER);
596 }
597 }
598 }
599
600 /* chilling monster reduces strength permanently */
601
602 if (on(*mp, CANCHILL) &&
603 (cur_armor == NULL || cur_armor->o_which != CRYSTAL_ARMOR))
604 {
605 msg("You cringe at the %s's chilling touch.", mname);
606
607 if (!is_wearing(R_SUSABILITY))
608 {
609 chg_str(-1, FALSE, TRUE);
610
611 if (lost_str == 0)
612 light_fuse(FUSE_RES_STRENGTH, 0, CHILLTIME, AFTER);
613 else
614 lengthen_fuse(FUSE_RES_STRENGTH, CHILLTIME);
615 }
616 }
617
618 /* itching monsters reduce dexterity (temporarily) */
619
620 if (on(*mp, CANITCH) && player.t_ctype != C_PALADIN
621 && !(player.t_ctype == C_NINJA && pstats.s_lvl > 12)
622 && !save(VS_POISON))
623 {
624 msg("The claws of the %s scratch you!", mname);
625
626 if (is_wearing(R_SUSABILITY))
627 msg("The scratch has no effect.");
628 else
629 {
630 msg("You feel a burning itch.");
631 turn_on(player, HASITCH);
632 chg_dext(-1, FALSE, TRUE);
633 light_fuse(FUSE_UNITCH, 0, roll(4, 6), AFTER);
634 }
635 }
636
637 /* a hugging monster may SQUEEEEEEEZE */
638
639 if (on(*mp, CANHUG) &&
640 (cur_armor == NULL || cur_armor->o_which != CRYSTAL_ARMOR))
641 {
642 if (roll(1, 20) >= 18 || roll(1, 20) >= 18)
643 {
644 msg("The %s squeezes you against itself.", mname);
645
646 if ((pstats.s_hpt -= roll(2, 8)) <= 0)
647 {
648 death(mp->t_index);
649 return TRUE;
650 }
651 }
652 }
653
654 /* a trampling monster may step on the player */
655
656 if (on(*mp, CANTRAMPLE))
657 {
658 if (roll(1, 20) >= 16 || roll(1, 20) >= 16)
659 {
660 msg("The %s steps on you.", mname);
661
662 if ((pstats.s_hpt -= roll(3, mp->t_stats.s_lvl)) <= 0)
663 {
664 death(mp->t_index);
665 return TRUE;
666 }
667 }
668 }
669
670 /* a disease-carrying monster may transmit the disease */
671
672 if (on(*mp, CANDISEASE) &&
673 (rnd(pstats.s_const) < mp->t_stats.s_lvl) &&
674 off(player, HASDISEASE))
675 {
676
677 if (is_wearing(R_HEALTH)
678 || (player.t_ctype == C_PALADIN)
679 || (player.t_ctype == C_NINJA &&
680 pstats.s_lvl > 6))
681 msg("The wound heals quickly.");
682 else
683 {
684 turn_on(player, HASDISEASE);
685 light_fuse(FUSE_CURE_DISEASE,0,roll(4,4) * SICKTIME, AFTER);
686 msg("You have contracted a disease!");
687 }
688 }
689
690 /* a rust monster will weaken your armor */
691
692 if (on(*mp, CANRUST))
693 {
694 if (cur_armor != NULL &&
695 cur_armor->o_which != SOFT_LEATHER &&
696 cur_armor->o_which != HEAVY_LEATHER &&
697 cur_armor->o_which != CUIRBOLILLI &&
698 cur_armor->o_which != PADDED_ARMOR &&
699 cur_armor->o_which != CRYSTAL_ARMOR &&
700 cur_armor->o_which != MITHRIL &&
701 !(cur_armor->o_flags & ISPROT) &&
702 cur_armor->o_ac < pstats.s_arm + 1)
703 {
704 msg("Your armor weakens!");
705 cur_armor->o_ac++;
706 }
707 else if (cur_armor != NULL &&
708 (cur_armor->o_flags & ISPROT) &&
709 cur_armor->o_which != SOFT_LEATHER &&
710 cur_armor->o_which != HEAVY_LEATHER &&
711 cur_armor->o_which != CUIRBOLILLI &&
712 cur_armor->o_which != PADDED_ARMOR &&
713 cur_armor->o_which != CRYSTAL_ARMOR &&
714 cur_armor->o_which != MITHRIL)
715 msg("The rust vanishes instantly!");
716 }
717
718 /* If a surprising monster hit you, you can see it now */
719
720 if (on(*mp, CANSURPRISE))
721 turn_off(*mp, CANSURPRISE);
722
723 /* an infesting monster will give you a parasite or rot */
724
725 if (on(*mp, CANINFEST) && rnd(pstats.s_const) < mp->t_stats.s_lvl)
726 {
727 if (is_wearing(R_HEALTH) || (player.t_ctype == C_PALADIN)
728 || (player.t_ctype == C_NINJA && pstats.s_lvl > 6))
729 msg("The wound quickly heals.");
730 else
731 {
732 turn_off(*mp, CANINFEST);
733 msg("You have contracted a parasitic infestation!");
734 infest_dam++;
735 turn_on(player, HASINFEST);
736 }
737 }
738
739 /* Some monsters have poisonous bites */
740
741 if (on(*mp, CANPOISON) && !save(VS_POISON))
742 {
743 if (is_wearing(R_SUSABILITY) || (player.t_ctype == C_PALADIN)
744 || (player.t_ctype == C_NINJA && pstats.s_lvl > 12))
745 msg("The sting has no effect on you!");
746 else
747 {
748 chg_str(-1, FALSE, FALSE);
749 msg("You feel a sting in your arm and now feel weaker.");
750 }
751 }
752
753 /* a hideous monster may cause fear by touching */
754
755 if (on(*mp, TOUCHFEAR))
756 {
757 turn_off(*mp, TOUCHFEAR);
758
759 if (!save(VS_WAND)&&!(on(player,ISFLEE)&&(player.t_chasee==mp)))
760 {
761 if (off(player, SUPERHERO)
762 && (player.t_ctype != C_PALADIN))
763 {
764 turn_on(player, ISFLEE);
765 player.t_ischasing = FALSE;
766 player.t_chasee = mp;
767 msg("The %s's touch terrifies you.", mname);
768 }
769 else
770 msg("The %s's touch feels cold and clammy.", mname);
771 }
772 }
773
774 /* some monsters will suffocate our hero */
775
776 if (on(*mp, CANSUFFOCATE) && (rnd(100) < 15) &&
777 (find_slot(FUSE_SUFFOCATE, FUSE) == NULL))
778 {
779 turn_on(*mp, DIDSUFFOCATE);
780 msg("The %s is beginning to suffocate you.",
781 mname);
782 light_fuse(FUSE_SUFFOCATE, 0, roll(4, 2), AFTER);
783 }
784
785 /* don't look now, you will get turned to stone */
786
787 if (on(*mp, TOUCHSTONE))
788 {
789 turn_off(*mp, TOUCHSTONE);
790
791 if (on(player, CANINWALL))
792 msg("The %s's touch has no effect.", mname);
793 else
794 {
795 if (!save(VS_PETRIFICATION) && rnd(100) < 3)
796 {
797 msg("Your body begins to solidify.");
798 msg("You are turned to stone !!! --More--");
799 wait_for(' ');
800 death(D_PETRIFY);
801 return TRUE;
802 }
803 else
804 {
805 msg("The %s's touch stiffens your limbs.", mname);
806 no_command = rnd(STONETIME) + 2;
807 }
808 }
809 }
810
811 /* Undead might drain energy levels */
812
813 if ((on(*mp, CANDRAIN) || on(*mp, DOUBLEDRAIN)) && rnd(100) < 15)
814 {
815 if (is_carrying(TR_AMULET))
816 msg("The Amulet protects you from the %s's negative energy!",
817 mname);
818 else
819 {
820 lower_level(mp->t_index);
821
822 if (on(*mp, DOUBLEDRAIN))
823 lower_level(mp->t_index);
824 }
825
826 turn_on(*mp, DIDDRAIN);
827 }
828
829 /* permanently drain a wisdom point */
830
831 if (on(*mp, DRAINWISDOM) && rnd(100) < 15)
832 {
833 int ring_str; /* Value of ring strengths */
834
835 /* Undo any ring changes */
836
837 ring_str = ring_value(R_ADDWISDOM) +
838 (on(player, POWERWISDOM) ? 10 : 0);
839
840 pstats.s_wisdom -= ring_str;
841
842 msg("You feel slightly less wise now.");
843
844 pstats.s_wisdom = max(pstats.s_wisdom - 1, 3);
845 max_stats.s_wisdom = pstats.s_wisdom;
846
847 /* Now put back the ring changes */
848
849 pstats.s_wisdom += ring_str;
850
851 }
852
853 /* permanently drain a intelligence point */
854
855 if (on(*mp, DRAINBRAIN) && rnd(100) < 15)
856 {
857 int ring_str; /* Value of ring strengths */
858
859 /* Undo any ring changes */
860
861 ring_str = ring_value(R_ADDINTEL) +
862 (on(player, POWERINTEL) ? 10 : 0);
863
864 pstats.s_intel -= ring_str;
865
866 msg("You feel slightly less intelligent now.");
867 pstats.s_intel = max(pstats.s_intel - 1, 3);
868 max_stats.s_intel = pstats.s_intel;
869
870 /* Now put back the ring changes */
871
872 pstats.s_intel += ring_str;
873 }
874
875 /* Violet fungi and others hold the hero */
876
877 if (on(*mp, CANHOLD) && off(*mp, DIDHOLD)
878 && !is_wearing(R_FREEDOM))
879 {
880 turn_on(player, ISHELD);
881 turn_on(*mp, DIDHOLD);
882 hold_count++;
883 }
884
885 /* suckers will suck blood and run away */
886
887 if (on(*mp, CANDRAW))
888 {
889 turn_off(*mp, CANDRAW);
890 turn_on(*mp, ISFLEE);
891 msg("The %s sates itself with your blood.", mname);
892
893 if ((pstats.s_hpt -= 12) <= 0)
894 {
895 death(mp->t_index);
896 return TRUE;
897 }
898 }
899
900 /* el stinkos will force a reduction in strength */
901
902 if (on(*mp, CANSMELL))
903 {
904 turn_off(*mp, CANSMELL);
905
906 if (save(VS_MAGIC) || is_wearing(R_SUSABILITY))
907 msg("You smell an unpleasant odor.");
908 else
909 {
910 int odor_str = -(rnd(6) + 1);
911
912 if (on(player, CANSCENT))
913 {
914 msg("You pass out from a foul odor.");
915 no_command += 4 + rnd(8);
916 }
917 else if (off(player, ISUNSMELL))
918 msg("You are overcome by a foul odor.");
919
920 if (lost_str == 0)
921 {
922 chg_str(odor_str, FALSE, TRUE);
923 light_fuse(FUSE_RES_STRENGTH, 0, SMELLTIME, AFTER);
924 }
925 else
926 lengthen_fuse(FUSE_RES_STRENGTH, SMELLTIME);
927 }
928 }
929
930 /* Paralyzation */
931
932 if (on(*mp, CANPARALYZE))
933 {
934 turn_off(*mp, CANPARALYZE);
935
936 if (!save(VS_PARALYZATION) && no_command == 0)
937 {
938 if (on(player, CANINWALL))
939 msg("The %s's touch has no effect.", mname);
940 else
941 {
942 msg("The %s's touch paralyzes you.", mname);
943 no_command = FREEZETIME;
944 }
945 }
946 }
947
948 /* Rotting */
949
950 if (on(*mp, CANROT))
951 {
952 turn_off(*mp, CANROT);
953 turn_on(*mp, DOROT);
954 }
955
956 /* some monsters steal gold */
957
958 if (on(*mp, STEALGOLD))
959 {
960 long lastpurse;
961 struct linked_list *item;
962 struct object *obj;
963
964 lastpurse = purse;
965 purse = (purse > GOLDCALC) ? purse - GOLDCALC : 0L;
966
967 if (!save(VS_MAGIC))
968 purse = (purse > (4*GOLDCALC)) ? purse-(4*GOLDCALC) : 0L;
969
970 if (purse != lastpurse)
971 {
972 msg("Your purse feels lighter.");
973
974 /* Give the gold to the thief */
975
976 for (item = mp->t_pack; item != NULL; item = next(item))
977 {
978 obj = OBJPTR(item);
979
980 if (obj->o_type == GOLD)
981 {
982 obj->o_count += lastpurse - purse;
983 break;
984 }
985 }
986
987 /* Did we do it? */
988
989 if (item == NULL) /* Then make some */
990 {
991 item = new_item(sizeof *obj);
992 obj = OBJPTR(item);
993 obj->o_type = GOLD;
994 obj->o_count = lastpurse - purse;
995 obj->o_hplus = obj->o_dplus = 0;
996 obj->o_damage = obj->o_hurldmg = "0d0";
997 obj->o_ac = 11;
998 obj->o_group = 0;
999 obj->o_flags = 0;
1000 obj->o_mark[0] = '\0';
1001 obj->o_pos = mp->t_pos;
1002
1003 attach(mp->t_pack, item);
1004 }
1005 }
1006
1007 if (rnd(2))
1008 turn_on(*mp, ISFLEE);
1009
1010 turn_on(*mp, ISINVIS);
1011 }
1012
1013 /* other monsters steal magic */
1014
1015 if (on(*mp, STEALMAGIC))
1016 {
1017 struct linked_list *list, *stealit;
1018 struct object *obj;
1019 int worth = 0;
1020
1021 stealit = NULL;
1022
1023 for (list = pack; list != NULL; list = next(list))
1024 {
1025 obj = OBJPTR(list);
1026
1027 if (rnd(33) == 0) /* some stuff degrades */
1028 {
1029 if (obj->o_flags & ISBLESSED)
1030 obj->o_flags &= ~ISBLESSED;
1031 else
1032 obj->o_flags |= ISCURSED;
1033
1034 msg("You feel nimble fingers reach into you pack.");
1035 }
1036
1037 if ((obj != cur_armor &&
1038 obj != cur_weapon &&
1039 obj != cur_ring[LEFT_1] &&
1040 obj != cur_ring[LEFT_2] &&
1041 obj != cur_ring[LEFT_3] &&
1042 obj != cur_ring[LEFT_4] &&
1043 obj != cur_ring[LEFT_5] &&
1044 obj != cur_ring[RIGHT_1] &&
1045 obj != cur_ring[RIGHT_2] &&
1046 obj != cur_ring[RIGHT_3] &&
1047 obj != cur_ring[RIGHT_4] &&
1048 obj != cur_ring[RIGHT_5] &&
1049 !(obj->o_flags & ISPROT) &&
1050 is_magic(obj)
1051 || level > 45)
1052 && get_worth(obj) > worth)
1053 {
1054 stealit = list;
1055 worth = get_worth(obj);
1056 }
1057 }
1058
1059 if (stealit != NULL)
1060 {
1061 struct object *newobj;
1062
1063 newobj = OBJPTR(stealit);
1064
1065 if (newobj->o_count > 1 && newobj->o_group == 0)
1066 {
1067 int oc;
1068 struct linked_list *nitem;
1069 struct object *op;
1070
1071 oc = --(newobj->o_count);
1072 newobj->o_count = 1;
1073 nitem = new_item(sizeof *newobj);
1074 op = OBJPTR(nitem);
1075 *op = *newobj;
1076
1077 msg("The %s stole %s!",mname,inv_name(newobj,LOWERCASE));
1078 newobj->o_count = oc;
1079 attach(mp->t_pack, nitem);
1080 }
1081 else
1082 {
1083 msg("The %s stole %s!",mname,inv_name(newobj,LOWERCASE));
1084 newobj->o_flags &= ~ISCURSED;
1085 dropcheck(newobj);
1086 rem_pack(newobj);
1087 attach(mp->t_pack, stealit);
1088
1089 if (newobj->o_type == ARTIFACT)
1090 has_artifact &= ~(1 << newobj->o_which);
1091 }
1092
1093 if (newobj->o_flags & ISOWNED)
1094 {
1095 turn_on(*mp, NOMOVE);
1096 msg("The %s is transfixed by your ownership spell.",
1097 mname);
1098 }
1099
1100 if (rnd(2))
1101 turn_on(*mp, ISFLEE);
1102
1103 turn_on(*mp, ISINVIS);
1104 updpack();
1105 }
1106 }
1107 }
1108 }
1109 else /* missed */
1110 {
1111 /* If the thing was trying to surprise, no good */
1112
1113 if (on(*mp, CANSURPRISE))
1114 turn_off(*mp, CANSURPRISE);
1115
1116 m_bounce(weapon, mname);
1117 }
1118
1119 count = 0;
1120
1121 status(FALSE);
1122
1123 return(did_hit);
1124 }
1125
1126
1127 /*
1128 mon_mon_attack()
1129 A monster attacks another monster
1130 */
1131
1132 int
1133 mon_mon_attack(struct thing *attacker, struct linked_list *mon, struct object *weapon, int thrown)
1134 {
1135 struct thing *attackee = THINGPTR(mon);
1136 int did_hit = FALSE;
1137 int ee_visible = cansee(attackee->t_pos.y, attackee->t_pos.x);
1138 int er_visible = cansee(attacker->t_pos.y, attacker->t_pos.x);
1139 char *mname1 = monsters[attacker->t_index].m_name;
1140 char *mname2 = monsters[attackee->t_index].m_name;
1141
1142 /* Similar monsters don't hit each other */
1143
1144 if (attacker->t_index == attackee->t_index)
1145 {
1146 if (attacker == THINGPTR(fam_ptr) && er_visible)
1147 msg("Master, I cannot hit one of my brethren.");
1148 if (!thrown && rnd(100) - attacker->t_stats.s_charisma + luck < 0)
1149 {
1150 if (er_visible)
1151 msg("Your %s has made a new ally.", mname1);
1152
1153 turn_on(*attackee, ISCHARMED);
1154 }
1155
1156 return(FALSE);
1157 }
1158
1159 /* stop running and any healing */
1160
1161 attackee->t_rest_hpt = attackee->t_rest_pow = 0;
1162 attacker->t_rest_hpt = attacker->t_rest_pow = 0;
1163
1164 if (roll_em(attacker, attackee, weapon, thrown,
1165 wield_weap(weapon, attacker)))
1166 {
1167 did_hit = TRUE;
1168
1169 if (ee_visible && on(*attackee, CANSURPRISE))
1170 turn_off(*attackee, CANSURPRISE);
1171
1172 if (ee_visible && er_visible && weapon != NULL)
1173 msg("The %s's %s hits the %s.", mname1,
1174 weaps[weapon->o_which].w_name, mname2);
1175 else if (ee_visible && er_visible)
1176 msg("The %s hits the %s.", mname1, mname2);
1177
1178 if (attackee->t_stats.s_hpt <= 0)
1179 {
1180 killed(attacker, mon, MESSAGE,
1181 on(*attacker, ISFAMILIAR) ? POINTS : NOPOINTS);
1182 return(TRUE);
1183 }
1184 }
1185 else /* missed */
1186 {
1187 did_hit = FALSE;
1188
1189 if (ee_visible && er_visible && weapon != NULL)
1190 msg("The %s's %s misses the %s.", mname1,
1191 weaps[weapon->o_which].w_name, mname2);
1192 else if (ee_visible && er_visible)
1193 msg("The %s misses the %s.", mname1, mname2);
1194 }
1195
1196 if (er_visible && !ee_visible)
1197 msg("The %s struggles with something.",mname1);
1198
1199 if (off(*attackee, ISMEAN) && off(*attackee, ISFAMILIAR))
1200 turn_on(*attackee, ISRUN);
1201
1202 count = 0;
1203
1204 status(FALSE);
1205
1206 return(did_hit);
1207 }
1208
1209
1210 /*
1211 swing()
1212 returns true if the swing hits
1213 */
1214
1215 int
1216 swing(int class, int at_lvl, int op_arm, int wplus)
1217 {
1218 int res = rnd(20) + 1;
1219 int need;
1220
1221 need = att_mat[class].base -
1222 att_mat[class].factor *
1223 ((min(at_lvl, att_mat[class].max_lvl) -
1224 att_mat[class].offset) / att_mat[class].range) +
1225 (10 - op_arm);
1226
1227 if (need > 20 && need <= 25)
1228 need = 20;
1229
1230 return(res + wplus >= need);
1231 }
1232
1233 /*
1234 init_exp()
1235 set up initial experience level change threshold
1236 */
1237
1238 void
1239 init_exp(void)
1240 {
1241 max_stats.s_exp = e_levels[player.t_ctype];
1242 }
1243
1244 /*
1245 next_exp_level()
1246 Do the next level arithmetic Returns number of levels to jump
1247 */
1248
1249 int
1250 next_exp_level(int print_message)
1251 {
1252 int level_jump = 0;
1253
1254 while (pstats.s_exp >= max_stats.s_exp)
1255 {
1256 pstats.s_exp -= max_stats.s_exp; /* excess experience points */
1257 level_jump++;
1258
1259 if (max_stats.s_exp < 0x3fffffffL) /* 2^30 - 1 */
1260 max_stats.s_exp *= 2L; /* twice as many for next */
1261 }
1262
1263 if (print_message)
1264 msg("You need %d more points to attain the %stitle of %s.",
1265 max_stats.s_exp - pstats.s_exp,
1266 (pstats.s_lvl > 14 ? "next " : ""),
1267 cnames[player.t_ctype][min(pstats.s_lvl, 14)]);
1268
1269 return(level_jump);
1270 }
1271
1272 /*
1273 check_level()
1274 Check to see if the guy has gone up a level.
1275 */
1276
1277 void
1278 check_level(void)
1279 {
1280 int num_jumped, j, add;
1281 int nsides;
1282
1283 if ((num_jumped = next_exp_level(NOMESSAGE)) <= 0)
1284 return;
1285
1286 pstats.s_lvl += num_jumped; /* new experience level */
1287
1288 switch (player.t_ctype)
1289 {
1290 case C_MAGICIAN:
1291 case C_ILLUSION: nsides = 4;
1292 break;
1293 case C_THIEF:
1294 case C_ASSASIN:
1295 case C_NINJA:
1296 case C_MONSTER:
1297 default: nsides = 6;
1298 break;
1299 case C_CLERIC:
1300 case C_DRUID: nsides = 8;
1301 break;
1302
1303 case C_FIGHTER:
1304 case C_PALADIN:
1305 case C_RANGER:
1306 nsides = 12;
1307 break;
1308 }
1309
1310 /* Take care of multi-level jumps */
1311
1312 for (add = 0, j = 0; j < num_jumped; j++)
1313 {
1314 int increase = roll(1, nsides) + const_bonus();
1315
1316 add += max(1, increase);
1317 }
1318
1319 max_stats.s_hpt += add;
1320 pstats.s_hpt += add;
1321
1322 msg("Welcome, %s, to level %d.",
1323 cnames[player.t_ctype][min(pstats.s_lvl - 1, 14)], pstats.s_lvl);
1324
1325 next_exp_level(MESSAGE);
1326
1327 /* Now add new spell points and learn new spells */
1328
1329 nsides = 16 - nsides;
1330
1331 for (add = 0, j = 0; j < num_jumped; j++)
1332 {
1333 int increase = roll(1, nsides) + int_wis_bonus();
1334
1335 add += max(1, increase);
1336 }
1337
1338 max_stats.s_power += add;
1339 pstats.s_power += add;
1340
1341 learn_new_spells();
1342
1343 /* Create a more powerful familiar (if player has one) */
1344
1345 if (on(player, HASFAMILIAR) && on(player, CANSUMMON))
1346 summon_monster((short) 0, FAMILIAR, NOMESSAGE);
1347 }
1348
1349 /*
1350 roll_em()
1351 Roll several attacks
1352 */
1353
1354 int
1355 roll_em(struct thing *att_er, struct thing *def_er, struct object *weap, int thrown, struct object *my_weapon)
1356 {
1357 struct stats *att = &att_er->t_stats;
1358 struct stats *def = &def_er->t_stats;
1359 int ndice, nsides, nplus, def_arm;
1360 char *cp;
1361 int prop_hplus = 0, prop_dplus = 0;
1362 int is_player = (att_er == &player);
1363 int did_hit = FALSE;
1364
1365 if (weap == NULL)
1366 cp = att->s_dmg;
1367 else if (!thrown)
1368 cp = weap->o_damage;
1369 else if ((weap->o_flags & ISMISL) && my_weapon != NULL &&
1370 my_weapon->o_which == weap->o_launch)
1371 {
1372 cp = weap->o_hurldmg;
1373 prop_hplus = my_weapon->o_hplus;
1374 prop_dplus = my_weapon->o_dplus;
1375 }
1376 else
1377 cp = (weap->o_flags & ISMISL ? weap->o_damage :
1378 weap->o_hurldmg);
1379
1380 for (;;)
1381 {
1382 int damage;
1383 int hplus = prop_hplus + (weap == NULL ? 0 : weap->o_hplus);
1384 int dplus = prop_dplus + (weap == NULL ? 0 : weap->o_dplus);
1385
1386 /* Is attacker weak? */
1387
1388 if (on(*att_er, HASSTINK))
1389 hplus -= 2;
1390
1391 if (is_player)
1392 {
1393 hplus += hitweight(); /* adjust for encumberence */
1394 dplus += hung_dam(); /* adjust damage for hungry player */
1395 dplus += ring_value(R_ADDDAM);
1396 }
1397
1398 ndice = atoi(cp);
1399
1400 if (cp == NULL || (cp = strchr(cp, 'd')) == NULL)
1401 break;
1402
1403 nsides = atoi(++cp);
1404
1405 if (cp != NULL && (cp = strchr(cp, '+')) != NULL)
1406 nplus = atoi(++cp);
1407 else
1408 nplus = 0;
1409
1410 if (def == &pstats)
1411 {
1412 if (on(*att_er, NOMETAL) && cur_armor != NULL &&
1413 (cur_armor->o_which == RING_MAIL ||
1414 cur_armor->o_which == SCALE_MAIL ||
1415 cur_armor->o_which == CHAIN_MAIL ||
1416 cur_armor->o_which == SPLINT_MAIL ||
1417 cur_armor->o_which == BANDED_MAIL ||
1418 cur_armor->o_which == GOOD_CHAIN ||
1419 cur_armor->o_which == PLATE_MAIL ||
1420 cur_armor->o_which == PLATE_ARMOR))
1421 def_arm = def->s_arm;
1422 else if (cur_armor != NULL)
1423 def_arm = cur_armor->o_ac - 10 + pstats.s_arm;
1424 else
1425 def_arm = def->s_arm;
1426 def_arm -= ring_value(R_PROTECT);
1427 }
1428 else
1429 def_arm = def->s_arm;
1430
1431 if ((weap != NULL && weap->o_type == WEAPON &&
1432 (weap->o_flags & ISSILVER) &&
1433 !save_throw(VS_MAGIC, def_er)) ||
1434 swing(att_er->t_ctype, att->s_lvl,
1435 def_arm - dext_prot(def->s_dext),
1436 hplus + str_plus(att->s_str) + dext_plus(att->s_dext)))
1437 {
1438 damage = roll(ndice, nsides) + dplus + nplus +
1439 add_dam(att->s_str);
1440
1441 /* Rangers do +1/lvl vs. ISLARGE */
1442
1443 if (att_er->t_ctype == C_RANGER && on(*def_er, ISLARGE))
1444 damage += pstats.s_lvl;
1445
1446 /* Ninja do +1 per lvl/2 */
1447
1448 if (att_er->t_ctype == C_NINJA)
1449 damage += pstats.s_lvl / 2;
1450
1451 /* Check for half damage monsters */
1452
1453 if (on(*def_er, HALFDAMAGE) && (weap != NULL) &&
1454 !((weap->o_flags & CANBURN) &&
1455 on(*def_er, CANBBURN)))
1456 damage /= 2;
1457
1458 /* undead get twice damage from silver weapons */
1459
1460 if (on(*def_er, ISUNDEAD) &&
1461 (weap != NULL) && (weap->o_flags & ISSILVER))
1462 damage *= 2;
1463
1464 /* Check for fireproof monsters */
1465
1466 if (on(*def_er, NOFIRE) && (weap != NULL) &&
1467 (weap->o_flags & CANBURN))
1468 damage = 0;
1469
1470 /* Check for metal proof monsters */
1471
1472 if (on(*def_er, NOMETAL) && (weap != NULL) &&
1473 (weap->o_flags & ISMETAL))
1474 damage = 0;
1475
1476 /* Check for monsters that ignore sharp weapons */
1477
1478 if (on(*def_er, NOSHARP) && (weap != NULL) &&
1479 (weap->o_flags & ISSHARP))
1480 damage = 0;
1481
1482 /* Check for poisoned weapons */
1483
1484 if ((weap != NULL) && (weap->o_flags & ISPOISON)
1485 && off(*def_er, ISUNDEAD)
1486 && !save_throw(VS_POISON, def_er))
1487 damage = max(damage, (def->s_hpt / 2) + 5);
1488
1489 /* Check for no-damage and division */
1490
1491 if (on(*def_er, BLOWDIVIDE) && rnd(3) == 0 &&
1492 !((weap != NULL) && (weap->o_flags & CANBURN)))
1493 {
1494 damage = 0;
1495 creat_mons(def_er, def_er->t_index, NOMESSAGE);
1496 }
1497
1498 damage = max(0, damage);
1499
1500 /*
1501 * sleeping monsters are backstabbed by certain
1502 * player classes, but only when they can see
1503 */
1504
1505 if (is_player && !thrown && damage > 0 &&
1506 (off(*def_er, ISRUN) || def_er->t_no_move > 0) &&
1507 (player.t_ctype == C_THIEF ||
1508 player.t_ctype == C_NINJA ||
1509 player.t_ctype == C_ASSASIN) &&
1510 off(player,ISBLIND)
1511 && (wield_ok(&player, my_weapon, NOMESSAGE))
1512 && (wear_ok(&player, cur_armor, NOMESSAGE)))
1513 {
1514 damage *= (pstats.s_lvl / 4 + 2);
1515
1516 msg("You backstabbed the %s %d times!",
1517 monsters[def_er->t_index].m_name,
1518 (pstats.s_lvl / 4) + 2);
1519
1520 if (player.t_ctype == C_NINJA ||
1521 player.t_ctype == C_ASSASIN)
1522 pstats.s_exp += def_er->t_stats.s_exp
1523 / 2;
1524 }
1525
1526 def->s_hpt -= damage; /* Do the damage */
1527
1528 debug("Hit %s for %d (%d) ",
1529 monsters[def_er->t_index].m_name, damage,
1530 def_er->t_stats.s_hpt);
1531
1532 if (is_player && is_wearing(R_VREGEN))
1533 {
1534 damage = (ring_value(R_VREGEN) * damage) / 3;
1535 pstats.s_hpt = min(max_stats.s_hpt,
1536 pstats.s_hpt + damage);
1537 }
1538
1539 /* stun monsters when taking more than 1/3 their max hpts */
1540
1541 if (is_player && !thrown && !did_hit &&
1542 (player.t_ctype == C_FIGHTER) &&
1543 (damage > def_er->maxstats.s_hpt / 3) )
1544 {
1545 if (def->s_hpt > 0)
1546 {
1547 msg("The %s has been stunned!",
1548 monsters[def_er->t_index].m_name);
1549 def_er->t_no_move += rnd(4) + 1;
1550 }
1551 pstats.s_exp += def_er->t_stats.s_exp / 4;
1552 }
1553
1554 did_hit = TRUE;
1555 }
1556
1557 if (cp == NULL || (cp = strchr(cp, '/')) == NULL)
1558 break;
1559
1560 cp++;
1561 }
1562
1563 return(did_hit);
1564 }
1565
1566 /*
1567 prname()
1568 Figure out the monsters name
1569 */
1570
1571 const char *
1572 prname(char *who)
1573 {
1574 if (on(player, ISBLIND))
1575 return(monstern);
1576 else
1577 return(who);
1578 }
1579
1580 /*
1581 hit()
1582 Print a message to indicate a succesful hit
1583 */
1584
1585 void
1586 hit(char *ee)
1587 {
1588 char *s;
1589
1590 if (fighting)
1591 return;
1592
1593 switch (rnd(15))
1594 {
1595 default: s = "hit"; break;
1596 case 1: s = "score an excellent hit on"; break;
1597 case 2: s = "injure"; break;
1598 case 3: s = "swing and hit"; break;
1599 case 4: s = "damage"; break;
1600 case 5: s = "barely nick"; break;
1601 case 6: s = "scratch"; break;
1602 case 7: s = "gouge a chunk out of"; break;
1603 case 8: s = "severely wound"; break;
1604 case 9: s = "counted coup on"; break;
1605 case 10: s = "drew blood from"; break;
1606 case 11: s = "nearly decapitate"; break;
1607 case 12: s = "deal a wacking great blow to"; break;
1608 }
1609
1610 msg("You %s the %s.", s, prname(ee));
1611 }
1612
1613 /*
1614 miss()
1615 Print a message to indicate a poor swing
1616 */
1617
1618 void
1619 miss(char *ee)
1620 {
1621 char *s;
1622
1623 if (fighting)
1624 return;
1625
1626 switch (rnd(10))
1627 {
1628 default: s = "miss"; break;
1629 case 1: s = "swing and miss"; break;
1630 case 2: s = "barely miss"; break;
1631 case 3: s = "don't hit"; break;
1632 case 4: s = "wildly windmill around"; break;
1633 case 5: s = "almost fumble while missing"; break;
1634 }
1635
1636 msg("You %s the %s.", s, prname(ee));
1637 }
1638
1639 /*
1640 save_throw()
1641 See if a creature save against something
1642 */
1643
1644 int
1645 save_throw(int which, struct thing *tp)
1646 {
1647 int need;
1648 int ring_bonus = 0;
1649 int armor_bonus = 0;
1650 int class_bonus = 0;
1651
1652 if (tp == &player)
1653 {
1654 if (player.t_ctype == C_PALADIN)
1655 class_bonus = 2;
1656
1657 ring_bonus = ring_value(R_PROTECT);
1658
1659 if (cur_armor != NULL && (which == VS_WAND ||
1660 which == VS_MAGIC))
1661 {
1662 if (cur_armor->o_which == MITHRIL)
1663 armor_bonus += 5;
1664 armor_bonus += (armors[cur_armor->o_which].a_class
1665 - cur_armor->o_ac);
1666 }
1667 }
1668
1669 need = 14 + which - tp->t_stats.s_lvl / 2 - ring_bonus -
1670 armor_bonus - class_bonus;
1671
1672 /* Roll of 1 always fails; 20 always saves */
1673
1674 if (need < 1)
1675 need = 1;
1676 else if (need > 20)
1677 need = 20;
1678
1679 return(roll(1, 20) >= need);
1680 }
1681
1682 /*
1683 save()
1684 See if he saves against various nasty things
1685 */
1686
1687 int
1688 save(int which)
1689 {
1690 return save_throw(which, &player);
1691 }
1692
1693 /*
1694 dext_plus()
1695 compute to-hit bonus for dexterity
1696 */
1697
1698 int
1699 dext_plus(int dexterity)
1700 {
1701 return ((dexterity - 10) / 3);
1702 }
1703
1704 /*
1705 * dext_prot: compute armor class bonus for dexterity
1706 */
1707
1708 int
1709 dext_prot(int dexterity)
1710 {
1711 return ((dexterity - 9) / 2);
1712 }
1713
1714 /*
1715 str_plus()
1716 compute bonus/penalties for strength on the "to hit" roll
1717 */
1718
1719 static const int strtohit[] =
1720 {
1721 0, 0, 0, -3, -2, -2, -1, -1,
1722 0, 0, 0, 0, 0, 0, 0, 0, 0,
1723 1, 1, 3, 3, 4, 4, 5, 6, 7
1724 };
1725
1726 int
1727 str_plus(int str)
1728 {
1729 int ret_val = str;
1730
1731 if (str < 3)
1732 ret_val = 3;
1733 else if (str > 25)
1734 ret_val = 25;
1735
1736 return(strtohit[ret_val]);
1737 }
1738
1739 /*
1740 add_dam()
1741 compute additional damage done for exceptionally high or low strength
1742 */
1743
1744 static const int str_damage[] =
1745 {
1746 0, 0, 0, -1, -1, -1, 0, 0,
1747 0, 0, 0, 0, 0, 0, 0, 0, 1,
1748 1, 2, 7, 8, 9, 10, 11, 12, 14
1749 };
1750
1751 int
1752 add_dam(int str)
1753 {
1754 int ret_val = str;
1755
1756 if (str < 3)
1757 ret_val = 3;
1758 else if (str > 25)
1759 ret_val = 25;
1760
1761 return(str_damage[ret_val]);
1762 }
1763
1764 /*
1765 hung_dam()
1766 Calculate damage depending on players hungry state
1767 */
1768
1769 int
1770 hung_dam(void)
1771 {
1772 int howmuch = 0;
1773
1774 switch (hungry_state)
1775 {
1776 case F_OK:
1777 case F_HUNGRY: howmuch = 0; break;
1778 case F_WEAK: howmuch = -1; break;
1779 case F_FAINT: howmuch = -2; break;
1780 }
1781
1782 return(howmuch);
1783 }
1784
1785 /*
1786 raise_level()
1787 The guy just magically went up a level.
1788 */
1789
1790 void
1791 raise_level(void)
1792 {
1793 pstats.s_exp = max_stats.s_exp;
1794 check_level();
1795 }
1796
1797 /*
1798 thunk()
1799 A missile hits a monster
1800 */
1801
1802 void
1803 thunk(struct object *weap, char *mname)
1804 {
1805 if (fighting)
1806 return;
1807
1808 if (weap->o_type == WEAPON)
1809 msg("The %s hits the %s.", weaps[weap->o_which].w_name, prname(mname));
1810 else
1811 msg("You hit the %s.", prname(mname));
1812 }
1813
1814 /*
1815 m_thunk()
1816 A missile from a monster hits the player
1817 */
1818
1819 void
1820 m_thunk(struct object *weap, char *mname)
1821 {
1822 if (fighting)
1823 return;
1824
1825 if (weap != NULL && weap->o_type == WEAPON)
1826 msg("The %s's %s hits you.",prname(mname),weaps[weap->o_which].w_name);
1827 else
1828 msg("The %s hits you.", prname(mname));
1829 }
1830
1831 /*
1832 bounce()
1833 A missile misses a monster
1834 */
1835
1836 void
1837 bounce(struct object *weap, char *mname)
1838 {
1839 if (fighting)
1840 return;
1841
1842 if (weap->o_type == WEAPON)
1843 msg("The %s misses the %s.",weaps[weap->o_which].w_name,prname(mname));
1844 else
1845 msg("You missed the %s.", prname(mname));
1846 }
1847
1848 /*
1849 m_bounce()
1850 A missile from a monster misses the player
1851 */
1852
1853 void
1854 m_bounce(struct object *weap, char *mname)
1855 {
1856 if (fighting)
1857 return;
1858
1859 if (weap != NULL && weap->o_type == WEAPON)
1860 msg("The %s's %s misses you.", prname(mname),
1861 weaps[weap->o_which].w_name);
1862 else
1863 msg("The %s misses you.", prname(mname));
1864 }
1865
1866 /*
1867 remove_monster()
1868 remove a monster from the screen
1869 */
1870
1871 void
1872 remove_monster(coord *mp, struct linked_list *item)
1873 {
1874 struct thing *tp = THINGPTR(item);
1875 char ch = tp->t_oldch;
1876
1877 mvwaddch(mw, mp->y, mp->x, ' ');
1878
1879 if (ch < 33 || ch == ' ')
1880 ch = CCHAR( mvwinch(stdscr, mp->y, mp->x) );
1881
1882 if (cansee(mp->y, mp->x))
1883 mvwaddch(cw, mp->y, mp->x, ch);
1884
1885 detach(mlist, item);
1886 discard(item);
1887 }
1888
1889 /*
1890 is_magic()
1891 Returns true if an object radiates magic
1892 */
1893
1894 int
1895 is_magic(struct object *obj)
1896 {
1897 switch (obj->o_type)
1898 {
1899 case ARMOR:
1900 return(obj->o_ac != armors[obj->o_which].a_class);
1901
1902 case WEAPON:
1903 return(obj->o_hplus != 0 || obj->o_dplus != 0);
1904
1905 case POTION:
1906 case SCROLL:
1907 case STICK:
1908 case RING:
1909 case ARTIFACT:
1910 return(TRUE);
1911 }
1912
1913 return(FALSE);
1914 }
1915
1916 /*
1917 killed()
1918 Called to put a monster to death
1919 */
1920
1921 void
1922 killed(struct thing *killer, struct linked_list *item, int print_message,
1923 int give_points)
1924 {
1925 struct linked_list *pitem, *nitem;
1926 struct thing *tp = THINGPTR(item);
1927 int visible = cansee(tp->t_pos.y, tp->t_pos.x);
1928 int is_player = (killer == (&player));
1929
1930 if (item == curr_mons)
1931 curr_mons = NULL;
1932 else if (item == next_mons)
1933 next_mons = next(next_mons);
1934
1935 if (on(*tp, WASSUMMONED))
1936 {
1937 extinguish_fuse(FUSE_UNSUMMON);
1938 turn_off(player, HASSUMMONED);
1939 }
1940
1941 if (print_message && visible)
1942 {
1943 if (is_player)
1944 addmsg("You have defeated ");
1945 else
1946 addmsg("The %s has defeated ",
1947 monsters[killer->t_index].m_name);
1948
1949 if (on(player, ISBLIND))
1950 msg("it.");
1951 else
1952 msg("the %s.", monsters[tp->t_index].m_name);
1953 }
1954 debug("Removing %s", monsters[tp->t_index].m_name);
1955 if (killer != NULL && item == fam_ptr) /* The player's familiar died */
1956 {
1957 turn_off(player, HASFAMILIAR);
1958 fam_ptr = NULL;
1959 msg("An incredible wave of sadness sweeps over you.");
1960 }
1961
1962 check_residue(tp);
1963
1964 if (is_player)
1965 {
1966 fighting = FALSE;
1967
1968 if (on(*tp, ISFRIENDLY))
1969 {
1970 msg("You feel a slight chill run up and down your spine.");
1971 luck++;
1972 }
1973 }
1974
1975 if (give_points)
1976 {
1977 if (killer != NULL)
1978 {
1979 killer->t_stats.s_exp += tp->t_stats.s_exp;
1980
1981 if (on(*killer, ISFAMILIAR))
1982 pstats.s_exp += tp->t_stats.s_exp;
1983 }
1984
1985 if (is_player)
1986 {
1987 switch (player.t_ctype)
1988 {
1989 case C_CLERIC:
1990 case C_PALADIN:
1991 if (on(*tp, ISUNDEAD) || on(*tp, ISUNIQUE))
1992 {
1993 pstats.s_exp += tp->t_stats.s_exp / 2;
1994 msg("You are to be commended for smiting the ungodly.");
1995 }
1996 break;
1997
1998 case C_DRUID:
1999 case C_RANGER:
2000 if (on(*tp, ISLARGE))
2001 {
2002 pstats.s_exp += tp->t_stats.s_exp / 2;
2003 msg("Congratulations on smiting a dangerous monster.");
2004 }
2005 break;
2006
2007 case C_MAGICIAN:
2008 case C_ILLUSION:
2009 if (on(*tp, DRAINBRAIN))
2010 {
2011 pstats.s_exp += tp->t_stats.s_exp / 2;
2012 msg("Congratulations on smiting a dangerous monster.");
2013 }
2014
2015 }
2016 }
2017 check_level();
2018 }
2019
2020 /* Empty the monsters pack */
2021
2022 for (pitem = tp->t_pack; pitem != NULL; pitem = nitem)
2023 {
2024 struct object *obj = OBJPTR(pitem);
2025
2026 nitem = next(pitem);
2027
2028 obj->o_pos = tp->t_pos;
2029 detach(tp->t_pack, pitem);
2030
2031 if (killer == NULL)
2032 discard(pitem);
2033 else
2034 fall(killer, pitem, FALSE, FALSE);
2035 }
2036
2037 remove_monster(&tp->t_pos, item);
2038 }
2039
2040
2041 /*
2042 wield_weap()
2043 Returns a pointer to the weapon the monster is wielding corresponding to the given thrown weapon
2044 */
2045
2046 struct object *
2047 wield_weap(struct object *weapon, struct thing *mp)
2048 {
2049 int look_for;
2050 struct linked_list *pitem;
2051
2052 if (weapon == NULL)
2053 return (NULL);
2054
2055 switch (weapon->o_which)
2056 {
2057 case BOLT:
2058 look_for = CROSSBOW;
2059 break;
2060
2061 case ARROW:
2062 look_for = BOW;
2063 break;
2064
2065 case SILVERARROW:
2066 case FLAMEARROW:
2067 look_for = BOW;
2068 break;
2069
2070 case ROCK:
2071 case BULLET:
2072 look_for = SLING;
2073 break;
2074
2075 default:
2076 return(NULL);
2077 }
2078
2079 for (pitem = mp->t_pack; pitem; pitem = next(pitem))
2080 if ((OBJPTR(pitem))->o_which == look_for)
2081 return(OBJPTR(pitem));
2082
2083 return (NULL);
2084 }
2085
2086 /*
2087 summon_help()
2088 Summon - see whether to summon help Returns TRUE if help comes, FALSE
2089 otherwise
2090 */
2091
2092 void
2093 summon_help(struct thing *mons, int force)
2094 {
2095 char *helpname;
2096 int which, i;
2097 char *mname = monsters[mons->t_index].m_name;
2098
2099 /* Try to summon if less than 1/3 max hit points */
2100
2101 if (on(*mons, CANSUMMON) &&
2102 (force == FORCE ||
2103 (mons->t_stats.s_hpt < mons->maxstats.s_hpt / 3) &&
2104 (rnd(40 * 10) < (mons->t_stats.s_lvl * mons->t_stats.s_intel))))
2105 {
2106 turn_off(*mons, CANSUMMON);
2107 msg("The %s summons its attendants!", mname);
2108 helpname = monsters[mons->t_index].m_typesum;
2109
2110 for (which = 1; which < nummonst; which++)
2111 {
2112 if (strcmp(helpname, monsters[which].m_name) == 0)
2113 break;
2114 }
2115
2116 if (which >= nummonst)
2117 {
2118 debug("Couldn't find summoned one.");
2119 return;
2120 }
2121
2122 /* summoned monster was genocided */
2123
2124 if (!monsters[which].m_normal)
2125 {
2126 msg("The %s becomes very annoyed at you!", mname);
2127
2128 if (on(*mons, ISSLOW))
2129 turn_off(*mons, ISSLOW);
2130 else
2131 turn_on(*mons, ISHASTE);
2132
2133 return;
2134 }
2135 else
2136 for (i = 0; i < monsters[mons->t_index].m_numsum; i++)
2137 {
2138 struct linked_list *ip;
2139 struct thing *tp;
2140
2141 if ((ip = creat_mons(mons, which, NOMESSAGE)) != NULL)
2142 {
2143 tp = THINGPTR(ip);
2144 turn_off(*tp, ISFRIENDLY);
2145 }
2146 }
2147 }
2148
2149 return;
2150 }
2151
2152 /*
2153 maxdamage()
2154 return the max damage a weapon can do
2155 */
2156
2157 int
2158 maxdamage(char *cp)
2159 {
2160 int ndice, nsides, nplus;
2161
2162 ndice = atoi(cp);
2163
2164 if (cp == NULL || (cp = strchr(cp, 'd')) == NULL)
2165 return(0);
2166
2167 nsides = atoi(++cp);
2168
2169 if (cp != NULL && (cp = strchr(cp, '+')) != NULL)
2170 nplus = atoi(++cp);
2171 else
2172 nplus = 0;
2173
2174 return(ndice * nsides + nplus);
2175 }