1 /* NetHack 3.6 mhitm.c $NHDT-Date: 1446854229 2015/11/06 23:57:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.83 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
8 extern boolean notonhead;
10 static NEARDATA boolean vis, far_noise;
11 static NEARDATA long noisetime;
12 static NEARDATA struct obj *otmp;
14 static const char brief_feeling[] =
15 "have a %s feeling for a moment, then it passes.";
17 STATIC_DCL char *FDECL(mon_nam_too, (char *, struct monst *, struct monst *));
18 STATIC_DCL int FDECL(hitmm, (struct monst *, struct monst *,
20 STATIC_DCL int FDECL(gazemm, (struct monst *, struct monst *,
22 STATIC_DCL int FDECL(gulpmm, (struct monst *, struct monst *,
24 STATIC_DCL int FDECL(explmm, (struct monst *, struct monst *,
26 STATIC_DCL int FDECL(mdamagem, (struct monst *, struct monst *,
28 STATIC_DCL void FDECL(mswingsm, (struct monst *, struct monst *,
30 STATIC_DCL void FDECL(noises, (struct monst *, struct attack *));
31 STATIC_DCL void FDECL(missmm, (struct monst *, struct monst *,
33 STATIC_DCL int FDECL(passivemm, (struct monst *, struct monst *,
36 /* Needed for the special case of monsters wielding vorpal blades (rare).
37 * If we use this a lot it should probably be a parameter to mdamagem()
38 * instead of a global variable.
42 /* returns mon_nam(mon) relative to other_mon; normal name unless they're
43 the same, in which case the reference is to {him|her|it} self */
45 mon_nam_too(outbuf, mon, other_mon)
47 struct monst *mon, *other_mon;
49 Strcpy(outbuf, mon_nam(mon));
51 switch (pronoun_gender(mon)) {
53 Strcpy(outbuf, "himself");
56 Strcpy(outbuf, "herself");
59 Strcpy(outbuf, "itself");
67 register struct monst *magr;
68 register struct attack *mattk;
70 boolean farq = (distu(magr->mx, magr->my) > 15);
72 if (!Deaf && (farq != far_noise || moves - noisetime > 10)) {
76 (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises",
77 farq ? " in the distance" : "");
83 missmm(magr, mdef, mattk)
84 register struct monst *magr, *mdef;
88 char buf[BUFSZ], mdef_name[BUFSZ];
91 if (!canspotmon(magr))
92 map_invisible(magr->mx, magr->my);
93 if (!canspotmon(mdef))
94 map_invisible(mdef->mx, mdef->my);
99 fmt = (could_seduce(magr, mdef, mattk) && !magr->mcan)
100 ? "%s pretends to be friendly to"
102 Sprintf(buf, fmt, Monnam(magr));
103 pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
109 * fightm() -- fight some other monster
112 * 0 - Monster did nothing.
113 * 1 - If the monster made an attack. The monster might have died.
115 * There is an exception to the above. If mtmp has the hero swallowed,
116 * then we report that the monster did nothing so it will continue to
119 /* have monsters fight each other */
122 register struct monst *mtmp;
124 register struct monst *mon, *nmon;
125 int result, has_u_swallowed;
129 /* perhaps the monster will resist Conflict */
130 if (resist(mtmp, RING_CLASS, 0, 0))
133 if (u.ustuck == mtmp) {
134 /* perhaps we're holding it... */
138 has_u_swallowed = (u.uswallow && (mtmp == u.ustuck));
140 for (mon = fmon; mon; mon = nmon) {
144 /* Be careful to ignore monsters that are already dead, since we
145 * might be calling this before we've cleaned them up. This can
146 * happen if the monster attacked a cockatrice bare-handedly, for
149 if (mon != mtmp && !DEADMONSTER(mon)) {
150 if (monnear(mtmp, mon->mx, mon->my)) {
151 if (!u.uswallow && (mtmp == u.ustuck)) {
153 pline("%s releases you!", Monnam(mtmp));
159 /* mtmp can be killed */
163 result = mattackm(mtmp, mon);
165 if (result & MM_AGR_DIED)
166 return 1; /* mtmp died */
168 * If mtmp has the hero swallowed, lie and say there
169 * was no attack (this allows mtmp to digest the hero).
174 /* Allow attacked monsters a chance to hit back. Primarily
175 * to allow monsters that resist conflict to respond.
177 if ((result & MM_HIT) && !(result & MM_DEF_DIED) && rn2(4)
178 && mon->movement >= NORMAL_SPEED) {
179 mon->movement -= NORMAL_SPEED;
181 (void) mattackm(mon, mtmp); /* return attack */
184 return (result & MM_HIT) ? 1 : 0;
192 * mdisplacem() -- attacker moves defender out of the way;
193 * returns same results as mattackm().
196 mdisplacem(magr, mdef, quietly)
197 register struct monst *magr, *mdef;
200 struct permonst *pa, *pd;
203 /* sanity checks; could matter if we unexpectedly get a long worm */
204 if (!magr || !mdef || magr == mdef)
206 pa = magr->data, pd = mdef->data;
207 tx = mdef->mx, ty = mdef->my; /* destination */
208 fx = magr->mx, fy = magr->my; /* current location */
209 if (m_at(fx, fy) != magr || m_at(tx, ty) != mdef)
212 /* The 1 in 7 failure below matches the chance in attack()
213 * for pet displacement.
218 /* Grid bugs cannot displace at an angle. */
219 if (pa == &mons[PM_GRID_BUG] && magr->mx != mdef->mx
220 && magr->my != mdef->my)
223 /* undetected monster becomes un-hidden if it is displaced */
224 if (mdef->mundetected)
225 mdef->mundetected = 0;
226 if (mdef->m_ap_type && mdef->m_ap_type != M_AP_MONSTER)
228 /* wake up the displaced defender */
230 mdef->mstrategy &= ~STRAT_WAITMASK;
231 finish_meating(mdef);
234 * Set up the visibility of action.
235 * You can observe monster displacement if you can see both of
236 * the monsters involved.
238 vis = (canspotmon(magr) && canspotmon(mdef));
240 if (touch_petrifies(pd) && !resists_ston(magr)) {
241 if (which_armor(magr, W_ARMG) != 0) {
242 if (poly_when_stoned(pa)) {
244 return MM_HIT; /* no damage during the polymorph */
246 if (!quietly && canspotmon(magr))
247 pline("%s turns to stone!", Monnam(magr));
250 return MM_HIT; /* lifesaved */
251 else if (magr->mtame && !vis)
252 You(brief_feeling, "peculiarly sad");
257 remove_monster(fx, fy); /* pick up from orig position */
258 remove_monster(tx, ty);
259 place_monster(magr, tx, ty); /* put down at target spot */
260 place_monster(mdef, fx, fy);
262 pline("%s moves %s out of %s way!", Monnam(magr), mon_nam(mdef),
263 is_rider(pa) ? "the" : mhis(magr));
264 newsym(fx, fy); /* see it */
265 newsym(tx, ty); /* all happen */
266 flush_screen(0); /* make sure it shows up */
272 * mattackm() -- a monster attacks another monster.
274 * --------- aggressor died
275 * / ------- defender died
276 * / / ----- defender was hit
285 * Each successive attack has a lower probability of hitting. Some rely on
286 * success of previous attacks. ** this doen't seem to be implemented -dl **
288 * In the case of exploding monsters, the monster dies as well.
292 register struct monst *magr, *mdef;
294 int i, /* loop counter */
295 tmp, /* amour class difference */
296 strike, /* hit this attack */
297 attk, /* attack attempted this time */
298 struck = 0, /* hit at least once */
299 res[NATTK]; /* results of all attacks */
300 struct attack *mattk, alt_attk;
301 struct permonst *pa, *pd;
304 return MM_MISS; /* mike@genat */
305 if (!magr->mcanmove || magr->msleeping)
310 /* Grid bugs cannot attack at an angle. */
311 if (pa == &mons[PM_GRID_BUG] && magr->mx != mdef->mx
312 && magr->my != mdef->my)
315 /* Calculate the armour class differential. */
316 tmp = find_mac(mdef) + magr->m_lev;
317 if (mdef->mconf || !mdef->mcanmove || mdef->msleeping) {
322 /* undetect monsters become un-hidden if they are attacked */
323 if (mdef->mundetected) {
324 mdef->mundetected = 0;
325 newsym(mdef->mx, mdef->my);
326 if (canseemon(mdef) && !sensemon(mdef)) {
328 You("dream of %s.", (mdef->data->geno & G_UNIQ)
330 : makeplural(m_monnam(mdef)));
332 pline("Suddenly, you notice %s.", a_monnam(mdef));
336 /* Elves hate orcs. */
337 if (is_elf(pa) && is_orc(pd))
340 /* Set up the visibility of action */
341 vis = (cansee(magr->mx, magr->my) && cansee(mdef->mx, mdef->my)
342 && (canspotmon(magr) || canspotmon(mdef)));
344 /* Set flag indicating monster has moved this turn. Necessary since a
345 * monster might get an attack out of sequence (i.e. before its move) in
346 * some cases, in which case this still counts as its move for the round
347 * and it shouldn't move again.
349 magr->mlstmv = monstermoves;
351 /* Now perform all attacks for the monster. */
352 for (i = 0; i < NATTK; i++) {
354 mattk = getmattk(pa, i, res, &alt_attk);
355 otmp = (struct obj *) 0;
357 switch (mattk->aatyp) {
358 case AT_WEAP: /* "hand to hand" attacks */
359 if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
360 magr->weapon_check = NEED_HTH_WEAPON;
361 if (mon_wield_item(magr) != 0)
364 possibly_unwield(magr, FALSE);
365 otmp = MON_WEP(magr);
369 mswingsm(magr, mdef, otmp);
370 tmp += hitval(otmp, mdef);
380 /* Nymph that teleported away on first attack? */
381 if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1)
383 /* Monsters won't attack cockatrices physically if they
384 * have a weapon instead. This instinct doesn't work for
385 * players, or under conflict or confusion.
387 if (!magr->mconf && !Conflict && otmp && mattk->aatyp != AT_WEAP
388 && touch_petrifies(mdef->data)) {
392 dieroll = rnd(20 + i);
393 strike = (tmp > dieroll);
394 /* KMH -- don't accumulate to-hit bonuses */
396 tmp -= hitval(otmp, mdef);
398 res[i] = hitmm(magr, mdef, mattk);
399 if ((mdef->data == &mons[PM_BLACK_PUDDING]
400 || mdef->data == &mons[PM_BROWN_PUDDING]) && otmp
401 && objects[otmp->otyp].oc_material == IRON
404 if (clone_mon(mdef, 0, 0)) {
408 Strcpy(buf, Monnam(mdef));
409 pline("%s divides as %s hits it!", buf,
415 missmm(magr, mdef, mattk);
418 case AT_HUGS: /* automatic if prev two attacks succeed */
419 strike = (i >= 2 && res[i - 1] == MM_HIT && res[i - 2] == MM_HIT);
421 res[i] = hitmm(magr, mdef, mattk);
427 res[i] = gazemm(magr, mdef, mattk);
431 res[i] = explmm(magr, mdef, mattk);
432 if (res[i] == MM_MISS) { /* cancelled--no attack */
436 strike = 1; /* automatic hit */
440 if (u.usteed && (mdef == u.usteed)) {
444 /* Engulfing attacks are directed at the hero if
447 if (u.uswallow && magr == u.ustuck)
450 if ((strike = (tmp > rnd(20 + i))))
451 res[i] = gulpmm(magr, mdef, mattk);
453 missmm(magr, mdef, mattk);
457 default: /* no attack */
463 if (attk && !(res[i] & MM_AGR_DIED))
464 res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED);
466 if (res[i] & MM_DEF_DIED)
469 if (res[i] & MM_AGR_DIED)
471 /* return if aggressor can no longer attack */
472 if (!magr->mcanmove || magr->msleeping)
475 struck = 1; /* at least one hit */
478 return (struck ? MM_HIT : MM_MISS);
481 /* Returns the result of mdamagem(). */
483 hitmm(magr, mdef, mattk)
484 register struct monst *magr, *mdef;
485 struct attack *mattk;
489 char buf[BUFSZ], mdef_name[BUFSZ];
491 if (!canspotmon(magr))
492 map_invisible(magr->mx, magr->my);
493 if (!canspotmon(mdef))
494 map_invisible(mdef->mx, mdef->my);
499 if ((compat = could_seduce(magr, mdef, mattk)) && !magr->mcan) {
500 Sprintf(buf, "%s %s", Monnam(magr),
501 mdef->mcansee ? "smiles at" : "talks to");
502 pline("%s %s %s.", buf, mon_nam(mdef),
503 compat == 2 ? "engagingly" : "seductively");
505 char magr_name[BUFSZ];
507 Strcpy(magr_name, Monnam(magr));
508 switch (mattk->aatyp) {
510 Sprintf(buf, "%s bites", magr_name);
513 Sprintf(buf, "%s stings", magr_name);
516 Sprintf(buf, "%s butts", magr_name);
519 Sprintf(buf, "%s touches", magr_name);
522 Sprintf(buf, "%s tentacles suck", s_suffix(magr_name));
525 if (magr != u.ustuck) {
526 Sprintf(buf, "%s squeezes", magr_name);
530 Sprintf(buf, "%s hits", magr_name);
532 pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
537 return mdamagem(magr, mdef, mattk);
540 /* Returns the same values as mdamagem(). */
542 gazemm(magr, mdef, mattk)
543 register struct monst *magr, *mdef;
544 struct attack *mattk;
549 Sprintf(buf, "%s gazes at", Monnam(magr));
550 pline("%s %s...", buf, mon_nam(mdef));
553 if (magr->mcan || !magr->mcansee
554 || (magr->minvis && !perceives(mdef->data)) || !mdef->mcansee
555 || mdef->msleeping) {
557 pline("but nothing happens.");
560 /* call mon_reflects 2x, first test, then, if visible, print message */
561 if (magr->data == &mons[PM_MEDUSA] && mon_reflects(mdef, (char *) 0)) {
563 (void) mon_reflects(mdef, "The gaze is reflected away by %s %s.");
565 if (mon_reflects(magr, (char *) 0)) {
568 magr, "The gaze is reflected away by %s %s.");
571 if (mdef->minvis && !perceives(magr->data)) {
572 if (canseemon(magr)) {
574 "%s doesn't seem to notice that %s gaze was reflected.",
575 Monnam(magr), mhis(magr));
580 pline("%s is turned to stone!", Monnam(magr));
588 return mdamagem(magr, mdef, mattk);
591 /* return True if magr is allowed to swallow mdef, False otherwise */
593 engulf_target(magr, mdef)
594 struct monst *magr, *mdef;
599 /* can't swallow something that's too big */
600 if (mdef->data->msize >= MZ_HUGE)
603 /* (hypothetical) engulfers who can pass through walls aren't
604 limited by rock|trees|bars */
605 if ((magr == &youmonst) ? Passes_walls : passes_walls(magr->data))
608 /* don't swallow something in a spot where attacker wouldn't
609 otherwise be able to move onto; we don't want to engulf
610 a wall-phaser and end up with a non-phaser inside a wall */
611 dx = mdef->mx, dy = mdef->my;
612 if (mdef == &youmonst)
613 dx = u.ux, dy = u.uy;
615 if (IS_ROCK(lev->typ) || closed_door(dx, dy) || IS_TREE(lev->typ)
616 /* not passes_bars(); engulfer isn't squeezing through */
617 || (lev->typ == IRONBARS && !is_whirly(magr->data)))
623 /* Returns the same values as mattackm(). */
625 gulpmm(magr, mdef, mattk)
626 register struct monst *magr, *mdef;
627 register struct attack *mattk;
629 xchar ax, ay, dx, dy;
634 if (!engulf_target(magr, mdef))
638 Sprintf(buf, "%s swallows", Monnam(magr));
639 pline("%s %s.", buf, mon_nam(mdef));
641 for (obj = mdef->minvent; obj; obj = obj->nobj)
642 (void) snuff_lit(obj);
645 * All of this manipulation is needed to keep the display correct.
646 * There is a flush at the next pline().
653 * Leave the defender in the monster chain at it's current position,
654 * but don't leave it on the screen. Move the aggressor to the
655 * defender's position.
657 remove_monster(ax, ay);
658 place_monster(magr, dx, dy);
659 newsym(ax, ay); /* erase old position */
660 newsym(dx, dy); /* update new position */
662 status = mdamagem(magr, mdef, mattk);
664 if ((status & (MM_AGR_DIED | MM_DEF_DIED))
665 == (MM_AGR_DIED | MM_DEF_DIED)) {
666 ; /* both died -- do nothing */
667 } else if (status & MM_DEF_DIED) { /* defender died */
669 * Note: remove_monster() was called in relmon(), wiping out
670 * magr from level.monsters[mdef->mx][mdef->my]. We need to
671 * put it back and display it. -kd
673 place_monster(magr, dx, dy);
675 /* aggressor moves to <dx,dy> and might encounter trouble there */
676 if (minliquid(magr) || (t_at(dx, dy) && mintrap(magr) == 2))
677 status |= MM_AGR_DIED;
678 } else if (status & MM_AGR_DIED) { /* aggressor died */
679 place_monster(mdef, dx, dy);
681 } else { /* both alive, put them back */
683 pline("%s is regurgitated!", Monnam(mdef));
685 place_monster(magr, ax, ay);
686 place_monster(mdef, dx, dy);
695 explmm(magr, mdef, mattk)
696 struct monst *magr, *mdef;
697 struct attack *mattk;
704 if (cansee(magr->mx, magr->my))
705 pline("%s explodes!", Monnam(magr));
709 result = mdamagem(magr, mdef, mattk);
711 /* Kill off aggressor if it didn't die. */
712 if (!(result & MM_AGR_DIED)) {
715 return result; /* life saved */
716 result |= MM_AGR_DIED;
718 if (magr->mtame) /* give this one even if it was visible */
719 You(brief_feeling, "melancholy");
725 * See comment at top of mattackm(), for return values.
728 mdamagem(magr, mdef, mattk)
729 register struct monst *magr, *mdef;
730 register struct attack *mattk;
734 struct permonst *pa = magr->data, *pd = mdef->data;
735 int armpro, num, tmp = d((int) mattk->damn, (int) mattk->damd),
739 if ((touch_petrifies(pd) /* or flesh_petrifies() */
740 || (mattk->adtyp == AD_DGST && pd == &mons[PM_MEDUSA]))
741 && !resists_ston(magr)) {
742 long protector = attk_protection((int) mattk->aatyp),
743 wornitems = magr->misc_worn_check;
745 /* wielded weapon gives same protection as gloves here */
750 || (protector != ~0L && (wornitems & protector) != protector)) {
751 if (poly_when_stoned(pa)) {
753 return MM_HIT; /* no damage during the polymorph */
756 pline("%s turns to stone!", Monnam(magr));
759 return MM_HIT; /* lifesaved */
760 else if (magr->mtame && !vis)
761 You(brief_feeling, "peculiarly sad");
766 /* cancellation factor is the same as when attacking the hero */
767 armpro = magic_negation(mdef);
768 cancelled = magr->mcan || !(rn2(10) >= 3 * armpro);
770 switch (mattk->adtyp) {
772 /* eating a Rider or its corpse is fatal */
775 pline("%s %s!", Monnam(magr),
776 (pd == &mons[PM_FAMINE])
777 ? "belches feebly, shrivels up and dies"
778 : (pd == &mons[PM_PESTILENCE])
779 ? "coughs spasmodically and collapses"
780 : "vomits violently and drops dead");
783 return 0; /* lifesaved */
784 else if (magr->mtame && !vis)
785 You(brief_feeling, "queasy");
788 if (flags.verbose && !Deaf)
789 verbalize("Burrrrp!");
791 /* Use up amulet of life saving */
792 if (!!(obj = mlifesaver(mdef)))
795 /* Is a corpse for nutrition possible? It may kill magr */
796 if (!corpse_chance(mdef, magr, TRUE) || magr->mhp < 1)
799 /* Pets get nutrition from swallowing monster whole.
800 * No nutrition from G_NOCORPSE monster, eg, undead.
801 * DGST monsters don't die from undead corpses
804 if (magr->mtame && !magr->isminion
805 && !(mvitals[num].mvflags & G_NOCORPSE)) {
806 struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE);
809 set_corpsenm(virtualcorpse, num);
810 nutrit = dog_nutrition(magr, virtualcorpse);
811 dealloc_obj(virtualcorpse);
813 /* only 50% nutrition, 25% of normal eating time */
814 if (magr->meating > 1)
815 magr->meating = (magr->meating + 3) / 4;
818 EDOG(magr)->hungrytime += nutrit;
825 pline("%s %s for a moment.", Monnam(mdef),
826 makeplural(stagger(pd, "stagger")));
839 if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
841 } else if (mattk->aatyp == AT_WEAP) {
843 if (otmp->otyp == CORPSE
844 && touch_petrifies(&mons[otmp->corpsenm]))
846 tmp += dmgval(otmp, mdef);
847 if (otmp->oartifact) {
848 (void) artifact_hit(magr, mdef, otmp, &tmp, dieroll);
851 | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
856 } else if (pa == &mons[PM_PURPLE_WORM] && pd == &mons[PM_SHRIEKER]) {
857 /* hack to enhance mm_aggression(); we don't want purple
858 worm's bite attack to kill a shrieker because then it
859 won't swallow the corpse; but if the target survives,
860 the subsequent engulf attack should accomplish that */
861 if (tmp >= mdef->mhp && mdef->mhp > 1)
871 pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk));
872 if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) {
874 pline("%s burns completely!", Monnam(mdef));
878 else if (mdef->mtame && !vis)
879 pline("May %s roast in peace.", mon_nam(mdef));
880 return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
882 tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
883 tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
884 if (resists_fire(mdef)) {
886 pline_The("fire doesn't seem to burn %s!", mon_nam(mdef));
887 shieldeff(mdef->mx, mdef->my);
888 golemeffects(mdef, AD_FIRE, tmp);
891 /* only potions damage resistant players in destroy_item */
892 tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
900 pline("%s is covered in frost!", Monnam(mdef));
901 if (resists_cold(mdef)) {
903 pline_The("frost doesn't seem to chill %s!", mon_nam(mdef));
904 shieldeff(mdef->mx, mdef->my);
905 golemeffects(mdef, AD_COLD, tmp);
908 tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
916 pline("%s gets zapped!", Monnam(mdef));
917 tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
918 if (resists_elec(mdef)) {
920 pline_The("zap doesn't shock %s!", mon_nam(mdef));
921 shieldeff(mdef->mx, mdef->my);
922 golemeffects(mdef, AD_ELEC, tmp);
925 /* only rings damage resistant players in destroy_item */
926 tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
933 if (resists_acid(mdef)) {
935 pline("%s is covered in acid, but it seems harmless.",
939 pline("%s is covered in acid!", Monnam(mdef));
940 pline("It burns %s!", mon_nam(mdef));
943 erode_armor(mdef, ERODE_CORRODE);
945 acid_damage(MON_WEP(mdef));
950 if (pd == &mons[PM_IRON_GOLEM]) {
952 pline("%s falls to pieces!", Monnam(mdef));
956 else if (mdef->mtame && !vis)
957 pline("May %s rust in peace.", mon_nam(mdef));
958 return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
960 erode_armor(mdef, ERODE_RUST);
961 mdef->mstrategy &= ~STRAT_WAITFORU;
967 erode_armor(mdef, ERODE_CORRODE);
968 mdef->mstrategy &= ~STRAT_WAITFORU;
974 if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) {
976 pline("%s falls to pieces!", Monnam(mdef));
980 else if (mdef->mtame && !vis)
981 pline("May %s rot in peace.", mon_nam(mdef));
982 return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
984 erode_armor(mdef, ERODE_CORRODE);
985 mdef->mstrategy &= ~STRAT_WAITFORU;
992 /* may die from the acid if it eats a stone-curing corpse */
993 if (munstone(mdef, FALSE))
995 if (poly_when_stoned(pd)) {
1000 if (!resists_ston(mdef)) {
1002 pline("%s turns to stone!", Monnam(mdef));
1007 else if (mdef->mtame && !vis)
1008 You(brief_feeling, "peculiarly sad");
1009 return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
1011 tmp = (mattk->adtyp == AD_STON ? 0 : 1);
1014 if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) {
1015 char mdef_Monnam[BUFSZ];
1016 /* save the name before monster teleports, otherwise
1017 we'll get "it" in the suddenly disappears message */
1019 Strcpy(mdef_Monnam, Monnam(mdef));
1020 mdef->mstrategy &= ~STRAT_WAITFORU;
1021 (void) rloc(mdef, TRUE);
1022 if (vis && !canspotmon(mdef) && mdef != u.usteed)
1023 pline("%s suddenly disappears!", mdef_Monnam);
1027 if (!cancelled && !mdef->msleeping
1028 && sleep_monst(mdef, rnd(10), -1)) {
1030 Strcpy(buf, Monnam(mdef));
1031 pline("%s is put to sleep by %s.", buf, mon_nam(magr));
1033 mdef->mstrategy &= ~STRAT_WAITFORU;
1038 if (!cancelled && mdef->mcanmove) {
1040 Strcpy(buf, Monnam(mdef));
1041 pline("%s is frozen by %s.", buf, mon_nam(magr));
1043 paralyze_monst(mdef, rnd(10));
1047 if (!cancelled && mdef->mspeed != MSLOW) {
1048 unsigned int oldspeed = mdef->mspeed;
1050 mon_adjust_speed(mdef, -1, (struct obj *) 0);
1051 mdef->mstrategy &= ~STRAT_WAITFORU;
1052 if (mdef->mspeed != oldspeed && vis)
1053 pline("%s slows down.", Monnam(mdef));
1057 /* Since confusing another monster doesn't have a real time
1058 * limit, setting spec_used would not really be right (though
1059 * we still should check for it).
1061 if (!magr->mcan && !mdef->mconf && !magr->mspec_used) {
1063 pline("%s looks confused.", Monnam(mdef));
1065 mdef->mstrategy &= ~STRAT_WAITFORU;
1069 if (can_blnd(magr, mdef, mattk->aatyp, (struct obj *) 0)) {
1070 register unsigned rnd_tmp;
1072 if (vis && mdef->mcansee)
1073 pline("%s is blinded.", Monnam(mdef));
1074 rnd_tmp = d((int) mattk->damn, (int) mattk->damd);
1075 if ((rnd_tmp += mdef->mblinded) > 127)
1077 mdef->mblinded = rnd_tmp;
1079 mdef->mstrategy &= ~STRAT_WAITFORU;
1084 if (!magr->mcan && haseyes(pd) && mdef->mcansee) {
1086 pline("%s looks %sconfused.", Monnam(mdef),
1087 mdef->mconf ? "more " : "");
1089 mdef->mstrategy &= ~STRAT_WAITFORU;
1094 if (!night() && (pa == &mons[PM_GREMLIN]))
1096 if (!magr->mcan && !rn2(10)) {
1097 mdef->mcan = 1; /* cancelled regardless of lifesave */
1098 mdef->mstrategy &= ~STRAT_WAITFORU;
1099 if (is_were(pd) && pd->mlet != S_HUMAN)
1101 if (pd == &mons[PM_CLAY_GOLEM]) {
1103 pline("Some writing vanishes from %s head!",
1104 s_suffix(mon_nam(mdef)));
1105 pline("%s is destroyed!", Monnam(mdef));
1110 else if (mdef->mtame && !vis)
1111 You(brief_feeling, "strangely sad");
1113 | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
1117 You_hear("laughter.");
1119 pline("%s chuckles.", Monnam(magr));
1127 /* technically incorrect; no check for stealing gold from
1128 * between mdef's feet...
1131 struct obj *gold = findgold(mdef->minvent);
1134 obj_extract_self(gold);
1135 add_to_minv(magr, gold);
1137 mdef->mstrategy &= ~STRAT_WAITFORU;
1139 Strcpy(buf, Monnam(magr));
1140 pline("%s steals some gold from %s.", buf, mon_nam(mdef));
1142 if (!tele_restrict(magr)) {
1143 (void) rloc(magr, TRUE);
1144 if (vis && !canspotmon(magr))
1145 pline("%s suddenly disappears!", buf);
1149 if (!cancelled && !rn2(3) && !resists_drli(mdef)) {
1152 pline("%s suddenly seems weaker!", Monnam(mdef));
1153 mdef->mhpmax -= tmp;
1154 if (mdef->m_lev == 0)
1158 /* Automatic kill if drained past level 0 */
1162 case AD_SITM: /* for now these are the same */
1166 /* find an object to steal, non-cursed if magr is tame */
1167 for (obj = mdef->minvent; obj; obj = obj->nobj)
1168 if (!magr->mtame || !obj->cursed)
1172 char onambuf[BUFSZ], mdefnambuf[BUFSZ];
1174 /* make a special x_monnam() call that never omits
1175 the saddle, and save it for later messages */
1177 x_monnam(mdef, ARTICLE_THE, (char *) 0, 0, FALSE));
1180 if (u.usteed == mdef && otmp == which_armor(mdef, W_SADDLE))
1181 /* "You can no longer ride <steed>." */
1182 dismount_steed(DISMOUNT_POLY);
1183 obj_extract_self(otmp);
1184 if (otmp->owornmask) {
1185 mdef->misc_worn_check &= ~otmp->owornmask;
1186 if (otmp->owornmask & W_WEP)
1188 otmp->owornmask = 0L;
1189 update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
1191 /* add_to_minv() might free otmp [if it merges] */
1193 Strcpy(onambuf, doname(otmp));
1194 (void) add_to_minv(magr, otmp);
1196 Strcpy(buf, Monnam(magr));
1197 pline("%s steals %s from %s!", buf, onambuf, mdefnambuf);
1199 possibly_unwield(mdef, FALSE);
1200 mdef->mstrategy &= ~STRAT_WAITFORU;
1201 mselftouch(mdef, (const char *) 0, FALSE);
1204 | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
1205 if (pa->mlet == S_NYMPH && !tele_restrict(magr)) {
1206 (void) rloc(magr, TRUE);
1207 if (vis && !canspotmon(magr))
1208 pline("%s suddenly disappears!", buf);
1214 if (!cancelled && !rn2(4))
1215 xdrainenergym(mdef, vis && mattk->aatyp != AT_ENGL);
1221 if (!cancelled && !rn2(8)) {
1223 pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
1224 mpoisons_subj(magr, mattk));
1225 if (resists_poison(mdef)) {
1227 pline_The("poison doesn't seem to affect %s.",
1234 pline_The("poison was deadly...");
1241 if (notonhead || !has_head(pd)) {
1243 pline("%s doesn't seem harmed.", Monnam(mdef));
1244 /* Not clear what to do for green slimes */
1248 if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) {
1250 Strcpy(buf, s_suffix(Monnam(mdef)));
1251 pline("%s helmet blocks %s attack to %s head.", buf,
1252 s_suffix(mon_nam(magr)), mhis(mdef));
1256 res = eat_brains(magr, mdef, vis, &tmp);
1260 break; /* physical damage only */
1261 if (!rn2(4) && !slimeproof(pd)) {
1262 if (!munslime(mdef, FALSE) && mdef->mhp > 0) {
1263 if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis))
1265 mdef->mstrategy &= ~STRAT_WAITFORU;
1268 /* munslime attempt could have been fatal,
1269 potentially to multiple monsters (SCR_FIRE) */
1281 case AD_WRAP: /* monsters cannot grab one another, it's too hard */
1286 /* there's no msomearmor() function, so just do damage */
1287 /* if (cancelled) break; */
1296 if ((mdef->mhp -= tmp) < 1) {
1297 if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */
1298 remove_monster(mdef->mx, mdef->my);
1299 mdef->mhp = 1; /* otherwise place_monster will complain */
1300 place_monster(mdef, mdef->mx, mdef->my);
1303 monkilled(mdef, "", (int) mattk->adtyp);
1305 return res; /* mdef lifesaved */
1306 else if (res == MM_AGR_DIED)
1307 return (MM_DEF_DIED | MM_AGR_DIED);
1309 if (mattk->adtyp == AD_DGST) {
1310 /* various checks similar to dog_eat and meatobj.
1311 * after monkilled() to provide better message ordering */
1312 if (mdef->cham >= LOW_PM) {
1313 (void) newcham(magr, (struct permonst *) 0, FALSE, TRUE);
1314 } else if (pd == &mons[PM_GREEN_SLIME] && !slimeproof(pa)) {
1315 (void) newcham(magr, &mons[PM_GREEN_SLIME], FALSE, TRUE);
1316 } else if (pd == &mons[PM_WRAITH]) {
1317 (void) grow_up(magr, (struct monst *) 0);
1318 /* don't grow up twice */
1319 return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED));
1320 } else if (pd == &mons[PM_NURSE]) {
1321 magr->mhp = magr->mhpmax;
1324 /* caveat: above digestion handling doesn't keep `pa' up to date */
1326 return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
1328 return (res == MM_AGR_DIED) ? MM_AGR_DIED : MM_HIT;
1332 paralyze_monst(mon, amt)
1341 mon->meating = 0; /* terminate any meal-in-progress */
1342 mon->mstrategy &= ~STRAT_WAITFORU;
1345 /* `mon' is hit by a sleep attack; return 1 if it's affected, 0 otherwise */
1347 sleep_monst(mon, amt, how)
1351 if (resists_sleep(mon)
1352 || (how >= 0 && resist(mon, (char) how, 0, NOTELL))) {
1353 shieldeff(mon->mx, mon->my);
1354 } else if (mon->mcanmove) {
1355 finish_meating(mon); /* terminate any meal-in-progress */
1356 amt += (int) mon->mfrozen;
1357 if (amt > 0) { /* sleep for N turns */
1359 mon->mfrozen = min(amt, 127);
1360 } else { /* sleep until awakened */
1368 /* sleeping grabber releases, engulfer doesn't; don't use for paralysis! */
1373 if ((mon->msleeping || !mon->mcanmove) && mon == u.ustuck
1374 && !sticks(youmonst.data) && !u.uswallow) {
1375 pline("%s grip relaxes.", s_suffix(Monnam(mon)));
1388 return; /* just in case */
1389 /* AD_ACID is handled in passivemm */
1390 if (dmgtype(mdef->data, AD_CORR))
1391 dmgtyp = ERODE_CORRODE;
1392 else if (dmgtype(mdef->data, AD_RUST))
1393 dmgtyp = ERODE_RUST;
1394 else if (dmgtype(mdef->data, AD_FIRE))
1395 dmgtyp = ERODE_BURN;
1398 (void) erode_obj(obj, NULL, dmgtyp, EF_GREASE | EF_VERBOSE);
1402 mswingsm(magr, mdef, otemp)
1403 struct monst *magr, *mdef;
1406 if (flags.verbose && !Blind && mon_visible(magr)) {
1407 pline("%s %s %s%s %s at %s.", Monnam(magr),
1408 (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
1409 (otemp->quan > 1L) ? "one of " : "", mhis(magr), xname(otemp),
1415 * Passive responses by defenders. Does not replicate responses already
1416 * handled above. Returns same values as mattackm.
1419 passivemm(magr, mdef, mhit, mdead)
1420 register struct monst *magr, *mdef;
1424 register struct permonst *mddat = mdef->data;
1425 register struct permonst *madat = magr->data;
1431 return (mdead | mhit); /* no passive attacks */
1432 if (mddat->mattk[i].aatyp == AT_NONE)
1435 if (mddat->mattk[i].damn)
1436 tmp = d((int) mddat->mattk[i].damn, (int) mddat->mattk[i].damd);
1437 else if (mddat->mattk[i].damd)
1438 tmp = d((int) mddat->mlevel + 1, (int) mddat->mattk[i].damd);
1442 /* These affect the enemy even if defender killed */
1443 switch (mddat->mattk[i].adtyp) {
1445 if (mhit && !rn2(2)) {
1446 Strcpy(buf, Monnam(magr));
1447 if (canseemon(magr))
1448 pline("%s is splashed by %s acid!", buf,
1449 s_suffix(mon_nam(mdef)));
1450 if (resists_acid(magr)) {
1451 if (canseemon(magr))
1452 pline("%s is not affected.", Monnam(magr));
1458 erode_armor(magr, ERODE_CORRODE);
1460 acid_damage(MON_WEP(magr));
1462 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1463 if (mhit && !mdef->mcan && otmp) {
1464 (void) drain_item(otmp);
1471 if (mdead || mdef->mcan)
1472 return (mdead | mhit);
1474 /* These affect the enemy only if defender is still alive */
1476 switch (mddat->mattk[i].adtyp) {
1477 case AD_PLYS: /* Floating eye */
1480 if (mddat == &mons[PM_FLOATING_EYE]) {
1483 if (magr->mcansee && haseyes(madat) && mdef->mcansee
1484 && (perceives(madat) || !mdef->minvis)) {
1485 Sprintf(buf, "%s gaze is reflected by %%s %%s.",
1486 s_suffix(Monnam(mdef)));
1487 if (mon_reflects(magr,
1488 canseemon(magr) ? buf : (char *) 0))
1489 return (mdead | mhit);
1490 Strcpy(buf, Monnam(magr));
1491 if (canseemon(magr))
1492 pline("%s is frozen by %s gaze!", buf,
1493 s_suffix(mon_nam(mdef)));
1494 paralyze_monst(magr, tmp);
1495 return (mdead | mhit);
1497 } else { /* gelatinous cube */
1498 Strcpy(buf, Monnam(magr));
1499 if (canseemon(magr))
1500 pline("%s is frozen by %s.", buf, mon_nam(mdef));
1501 paralyze_monst(magr, tmp);
1502 return (mdead | mhit);
1506 if (resists_cold(magr)) {
1507 if (canseemon(magr)) {
1508 pline("%s is mildly chilly.", Monnam(magr));
1509 golemeffects(magr, AD_COLD, tmp);
1514 if (canseemon(magr))
1515 pline("%s is suddenly very cold!", Monnam(magr));
1516 mdef->mhp += tmp / 2;
1517 if (mdef->mhpmax < mdef->mhp)
1518 mdef->mhpmax = mdef->mhp;
1519 if (mdef->mhpmax > ((int) (mdef->m_lev + 1) * 8))
1520 (void) split_mon(mdef, magr);
1525 if (canseemon(magr))
1526 pline("%s %s...", Monnam(magr),
1527 makeplural(stagger(magr->data, "stagger")));
1532 if (resists_fire(magr)) {
1533 if (canseemon(magr)) {
1534 pline("%s is mildly warmed.", Monnam(magr));
1535 golemeffects(magr, AD_FIRE, tmp);
1540 if (canseemon(magr))
1541 pline("%s is suddenly very hot!", Monnam(magr));
1544 if (resists_elec(magr)) {
1545 if (canseemon(magr)) {
1546 pline("%s is mildly tingled.", Monnam(magr));
1547 golemeffects(magr, AD_ELEC, tmp);
1552 if (canseemon(magr))
1553 pline("%s is jolted with electricity!", Monnam(magr));
1563 if ((magr->mhp -= tmp) <= 0) {
1564 monkilled(magr, "", (int) mddat->mattk[i].adtyp);
1565 return (mdead | mhit | MM_AGR_DIED);
1567 return (mdead | mhit);
1570 /* hero or monster has successfully hit target mon with drain energy attack */
1572 xdrainenergym(mon, givemsg)
1576 if (mon->mspec_used < 20 /* limit draining */
1577 && (attacktype(mon->data, AT_MAGC)
1578 || attacktype(mon->data, AT_BREA))) {
1579 mon->mspec_used += d(2, 2);
1581 pline("%s seems lethargic.", Monnam(mon));
1585 /* "aggressive defense"; what type of armor prevents specified attack
1586 from touching its target? */
1588 attk_protection(aatyp)
1601 w_mask = ~0L; /* special case; no defense needed */
1606 w_mask = W_ARMG; /* caller needs to check for weapon */
1615 w_mask = (W_ARMC | W_ARMG); /* attacker needs both to be protected */
1622 w_mask = 0L; /* no defense available */