OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / mhitm.c
1 /*      SCCS Id: @(#)mhitm.c    3.4     2003/01/02      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6 #include "artifact.h"
7 #include "edog.h"
8
9 extern boolean notonhead;
10
11 #ifdef OVLB
12
13 static NEARDATA boolean vis, far_noise;
14 static NEARDATA long noisetime;
15 static NEARDATA struct obj *otmp;
16
17 static const char brief_feeling[] =
18         "have a %s feeling for a moment, then it passes.";
19
20 STATIC_DCL char *FDECL(mon_nam_too, (char *,struct monst *,struct monst *));
21 STATIC_DCL void FDECL(mrustm, (struct monst *, struct monst *, struct obj *));
22 STATIC_DCL int FDECL(hitmm, (struct monst *,struct monst *,struct attack *));
23 STATIC_DCL int FDECL(gazemm, (struct monst *,struct monst *,struct attack *));
24 STATIC_DCL int FDECL(gulpmm, (struct monst *,struct monst *,struct attack *));
25 STATIC_DCL int FDECL(explmm, (struct monst *,struct monst *,struct attack *));
26 STATIC_DCL int FDECL(mdamagem, (struct monst *,struct monst *,struct attack *));
27 STATIC_DCL void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *));
28 STATIC_DCL void FDECL(noises,(struct monst *,struct attack *));
29 STATIC_DCL void FDECL(missmm,(struct monst *,struct monst *,struct attack *));
30 STATIC_DCL int FDECL(passivemm, (struct monst *, struct monst *, BOOLEAN_P, int));
31
32 /* Needed for the special case of monsters wielding vorpal blades (rare).
33  * If we use this a lot it should probably be a parameter to mdamagem()
34  * instead of a global variable.
35  */
36 static int dieroll;
37
38 /* returns mon_nam(mon) relative to other_mon; normal name unless they're
39    the same, in which case the reference is to {him|her|it} self */
40 STATIC_OVL char *
41 mon_nam_too(outbuf, mon, other_mon)
42 char *outbuf;
43 struct monst *mon, *other_mon;
44 {
45         Strcpy(outbuf, mon_nam(mon));
46         if (mon == other_mon)
47             switch (pronoun_gender(mon)) {
48             case 0:     Strcpy(outbuf, "himself");  break;
49             case 1:     Strcpy(outbuf, "herself");  break;
50             default:    Strcpy(outbuf, "itself"); break;
51             }
52         return outbuf;
53 }
54
55 STATIC_OVL void
56 noises(magr, mattk)
57         register struct monst *magr;
58         register struct attack *mattk;
59 {
60         boolean farq = (distu(magr->mx, magr->my) > 15);
61
62         if(flags.soundok && (farq != far_noise || moves-noisetime > 10)) {
63                 far_noise = farq;
64                 noisetime = moves;
65                 You_hear("%s%s.",
66                         (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises",
67                         farq ? " in the distance" : "");
68         }
69 }
70
71 STATIC_OVL
72 void
73 missmm(magr, mdef, mattk)
74         register struct monst *magr, *mdef;
75         struct attack *mattk;
76 {
77         const char *fmt;
78         char buf[BUFSZ], mdef_name[BUFSZ];
79
80         if (vis) {
81                 if (!canspotmon(magr))
82                     map_invisible(magr->mx, magr->my);
83                 if (!canspotmon(mdef))
84                     map_invisible(mdef->mx, mdef->my);
85                 if (mdef->m_ap_type) seemimic(mdef);
86                 if (magr->m_ap_type) seemimic(magr);
87                 fmt = (could_seduce(magr,mdef,mattk) && !magr->mcan) ?
88                         "%s pretends to be friendly to" : "%s misses";
89                 Sprintf(buf, fmt, Monnam(magr));
90                 pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
91         } else  noises(magr, mattk);
92 }
93
94 /*
95  *  fightm()  -- fight some other monster
96  *
97  *  Returns:
98  *      0 - Monster did nothing.
99  *      1 - If the monster made an attack.  The monster might have died.
100  *
101  *  There is an exception to the above.  If mtmp has the hero swallowed,
102  *  then we report that the monster did nothing so it will continue to
103  *  digest the hero.
104  */
105 int
106 fightm(mtmp)            /* have monsters fight each other */
107         register struct monst *mtmp;
108 {
109         register struct monst *mon, *nmon;
110         int result, has_u_swallowed;
111 #ifdef LINT
112         nmon = 0;
113 #endif
114         /* perhaps the monster will resist Conflict */
115         if(resist(mtmp, RING_CLASS, 0, 0))
116             return(0);
117
118         if(u.ustuck == mtmp) {
119             /* perhaps we're holding it... */
120             if(itsstuck(mtmp))
121                 return(0);
122         }
123         has_u_swallowed = (u.uswallow && (mtmp == u.ustuck));
124
125         for(mon = fmon; mon; mon = nmon) {
126             nmon = mon->nmon;
127             if(nmon == mtmp) nmon = mtmp->nmon;
128             /* Be careful to ignore monsters that are already dead, since we
129              * might be calling this before we've cleaned them up.  This can
130              * happen if the monster attacked a cockatrice bare-handedly, for
131              * instance.
132              */
133             if(mon != mtmp && !DEADMONSTER(mon)) {
134                 if(monnear(mtmp,mon->mx,mon->my)) {
135                     if(!u.uswallow && (mtmp == u.ustuck)) {
136                         if(!rn2(4)) {
137                             pline("%s releases you!", Monnam(mtmp));
138                             u.ustuck = 0;
139                         } else
140                             break;
141                     }
142
143                     /* mtmp can be killed */
144                     bhitpos.x = mon->mx;
145                     bhitpos.y = mon->my;
146                     notonhead = 0;
147                     result = mattackm(mtmp,mon);
148
149                     if (result & MM_AGR_DIED) return 1; /* mtmp died */
150                     /*
151                      *  If mtmp has the hero swallowed, lie and say there
152                      *  was no attack (this allows mtmp to digest the hero).
153                      */
154                     if (has_u_swallowed) return 0;
155
156                     /* Allow attacked monsters a chance to hit back. Primarily
157                      * to allow monsters that resist conflict to respond.
158                      */
159                     if ((result & MM_HIT) && !(result & MM_DEF_DIED) &&
160                         rn2(4) && mon->movement >= NORMAL_SPEED) {
161                         mon->movement -= NORMAL_SPEED;
162                         notonhead = 0;
163                         (void) mattackm(mon, mtmp);     /* return attack */
164                     }
165
166                     return ((result & MM_HIT) ? 1 : 0);
167                 }
168             }
169         }
170         return 0;
171 }
172
173 /*
174  * mattackm() -- a monster attacks another monster.
175  *
176  * This function returns a result bitfield:
177  *
178  *          --------- aggressor died
179  *         /  ------- defender died
180  *        /  /  ----- defender was hit
181  *       /  /  /
182  *      x  x  x
183  *
184  *      0x4     MM_AGR_DIED
185  *      0x2     MM_DEF_DIED
186  *      0x1     MM_HIT
187  *      0x0     MM_MISS
188  *
189  * Each successive attack has a lower probability of hitting.  Some rely on the
190  * success of previous attacks.  ** this doen't seem to be implemented -dl **
191  *
192  * In the case of exploding monsters, the monster dies as well.
193  */
194 int
195 mattackm(magr, mdef)
196     register struct monst *magr,*mdef;
197 {
198     int             i,          /* loop counter */
199                     tmp,        /* amour class difference */
200                     strike,     /* hit this attack */
201                     attk,       /* attack attempted this time */
202                     struck = 0, /* hit at least once */
203                     res[NATTK]; /* results of all attacks */
204     struct attack   *mattk, alt_attk;
205     struct permonst *pa, *pd;
206
207     if (!magr || !mdef) return(MM_MISS);                /* mike@genat */
208     if (!magr->mcanmove || magr->msleeping) return(MM_MISS);
209     pa = magr->data;  pd = mdef->data;
210
211     /* Grid bugs cannot attack at an angle. */
212     if (pa == &mons[PM_GRID_BUG] && magr->mx != mdef->mx
213                                                 && magr->my != mdef->my)
214         return(MM_MISS);
215
216     /* Calculate the armour class differential. */
217     tmp = find_mac(mdef) + magr->m_lev;
218     if (mdef->mconf || !mdef->mcanmove || mdef->msleeping) {
219         tmp += 4;
220         mdef->msleeping = 0;
221     }
222
223     /* undetect monsters become un-hidden if they are attacked */
224     if (mdef->mundetected) {
225         mdef->mundetected = 0;
226         newsym(mdef->mx, mdef->my);
227         if(canseemon(mdef) && !sensemon(mdef)) {
228             if (u.usleep) You("dream of %s.",
229                                 (mdef->data->geno & G_UNIQ) ?
230                                 a_monnam(mdef) : makeplural(m_monnam(mdef)));
231             else pline("Suddenly, you notice %s.", a_monnam(mdef));
232         }
233     }
234
235     /* Elves hate orcs. */
236     if (is_elf(pa) && is_orc(pd)) tmp++;
237
238
239     /* Set up the visibility of action */
240     vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my) && (canspotmon(magr) || canspotmon(mdef)));
241
242     /*  Set flag indicating monster has moved this turn.  Necessary since a
243      *  monster might get an attack out of sequence (i.e. before its move) in
244      *  some cases, in which case this still counts as its move for the round
245      *  and it shouldn't move again.
246      */
247     magr->mlstmv = monstermoves;
248
249     /* Now perform all attacks for the monster. */
250     for (i = 0; i < NATTK; i++) {
251         res[i] = MM_MISS;
252         mattk = getmattk(pa, i, res, &alt_attk);
253         otmp = (struct obj *)0;
254         attk = 1;
255         switch (mattk->aatyp) {
256             case AT_WEAP:               /* "hand to hand" attacks */
257                 if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
258                     magr->weapon_check = NEED_HTH_WEAPON;
259                     if (mon_wield_item(magr) != 0) return 0;
260                 }
261                 possibly_unwield(magr, FALSE);
262                 otmp = MON_WEP(magr);
263
264                 if (otmp) {
265                     if (vis) mswingsm(magr, mdef, otmp);
266                     tmp += hitval(otmp, mdef);
267                 }
268                 /* fall through */
269             case AT_CLAW:
270             case AT_KICK:
271             case AT_BITE:
272             case AT_STNG:
273             case AT_TUCH:
274             case AT_BUTT:
275             case AT_TENT:
276                 /* Nymph that teleported away on first attack? */
277                 if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1)
278                     return MM_MISS;
279                 /* Monsters won't attack cockatrices physically if they
280                  * have a weapon instead.  This instinct doesn't work for
281                  * players, or under conflict or confusion. 
282                  */
283                 if (!magr->mconf && !Conflict && otmp &&
284                     mattk->aatyp != AT_WEAP && touch_petrifies(mdef->data)) {
285                     strike = 0;
286                     break;
287                 }
288                 dieroll = rnd(20 + i);
289                 strike = (tmp > dieroll);
290                 /* KMH -- don't accumulate to-hit bonuses */
291                 if (otmp)
292                     tmp -= hitval(otmp, mdef);
293                 if (strike) {
294                     res[i] = hitmm(magr, mdef, mattk);
295                     if((mdef->data == &mons[PM_BLACK_PUDDING] || mdef->data == &mons[PM_BROWN_PUDDING])
296                        && otmp && objects[otmp->otyp].oc_material == IRON
297                        && mdef->mhp > 1 && !mdef->mcan)
298                     {
299                         if (clone_mon(mdef, 0, 0)) {
300                             if (vis) {
301                                 char buf[BUFSZ];
302
303                                 Strcpy(buf, Monnam(mdef));
304                                 pline("%s divides as %s hits it!", buf, mon_nam(magr));
305                             }
306                         }
307                     }
308                 } else
309                     missmm(magr, mdef, mattk);
310                 break;
311
312             case AT_HUGS:       /* automatic if prev two attacks succeed */
313                 strike = (i >= 2 && res[i-1] == MM_HIT && res[i-2] == MM_HIT);
314                 if (strike)
315                     res[i] = hitmm(magr, mdef, mattk);
316
317                 break;
318
319             case AT_GAZE:
320                 strike = 0;     /* will not wake up a sleeper */
321                 res[i] = gazemm(magr, mdef, mattk);
322                 break;
323
324             case AT_EXPL:
325                 res[i] = explmm(magr, mdef, mattk);
326                 if (res[i] == MM_MISS) { /* cancelled--no attack */
327                     strike = 0;
328                     attk = 0;
329                 } else
330                     strike = 1; /* automatic hit */
331                 break;
332
333             case AT_ENGL:
334 #ifdef STEED
335                 if (u.usteed && (mdef == u.usteed)) {
336                     strike = 0;
337                     break;
338                 } 
339 #endif
340                 /* Engulfing attacks are directed at the hero if
341                  * possible. -dlc
342                  */
343                 if (u.uswallow && magr == u.ustuck)
344                     strike = 0;
345                 else {
346                     if ((strike = (tmp > rnd(20+i))))
347                         res[i] = gulpmm(magr, mdef, mattk);
348                     else
349                         missmm(magr, mdef, mattk);
350                 }
351                 break;
352
353             default:            /* no attack */
354                 strike = 0;
355                 attk = 0;
356                 break;
357         }
358
359         if (attk && !(res[i] & MM_AGR_DIED))
360             res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED);
361
362         if (res[i] & MM_DEF_DIED) return res[i];
363
364         /*
365          *  Wake up the defender.  NOTE:  this must follow the check
366          *  to see if the defender died.  We don't want to modify
367          *  unallocated monsters!
368          */
369         if (strike) mdef->msleeping = 0;
370
371         if (res[i] & MM_AGR_DIED)  return res[i];
372         /* return if aggressor can no longer attack */
373         if (!magr->mcanmove || magr->msleeping) return res[i];
374         if (res[i] & MM_HIT) struck = 1;        /* at least one hit */
375     }
376
377     return(struck ? MM_HIT : MM_MISS);
378 }
379
380 /* Returns the result of mdamagem(). */
381 STATIC_OVL int
382 hitmm(magr, mdef, mattk)
383         register struct monst *magr,*mdef;
384         struct  attack *mattk;
385 {
386         if(vis){
387                 int compat;
388                 char buf[BUFSZ], mdef_name[BUFSZ];
389
390                 if (!canspotmon(magr))
391                     map_invisible(magr->mx, magr->my);
392                 if (!canspotmon(mdef))
393                     map_invisible(mdef->mx, mdef->my);
394                 if(mdef->m_ap_type) seemimic(mdef);
395                 if(magr->m_ap_type) seemimic(magr);
396                 if((compat = could_seduce(magr,mdef,mattk)) && !magr->mcan) {
397                         Sprintf(buf, "%s %s", Monnam(magr),
398                                 mdef->mcansee ? "smiles at" : "talks to");
399                         pline("%s %s %s.", buf, mon_nam(mdef),
400                                 compat == 2 ?
401                                         "engagingly" : "seductively");
402                 } else {
403                     char magr_name[BUFSZ];
404
405                     Strcpy(magr_name, Monnam(magr));
406                     switch (mattk->aatyp) {
407                         case AT_BITE:
408                                 Sprintf(buf,"%s bites", magr_name);
409                                 break;
410                         case AT_STNG:
411                                 Sprintf(buf,"%s stings", magr_name);
412                                 break;
413                         case AT_BUTT:
414                                 Sprintf(buf,"%s butts", magr_name);
415                                 break;
416                         case AT_TUCH:
417                                 Sprintf(buf,"%s touches", magr_name);
418                                 break;
419                         case AT_TENT:
420                                 Sprintf(buf, "%s tentacles suck",
421                                         s_suffix(magr_name));
422                                 break;
423                         case AT_HUGS:
424                                 if (magr != u.ustuck) {
425                                     Sprintf(buf,"%s squeezes", magr_name);
426                                     break;
427                                 }
428                         default:
429                                 Sprintf(buf,"%s hits", magr_name);
430                     }
431                     pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
432                 }
433         } else  noises(magr, mattk);
434         return(mdamagem(magr, mdef, mattk));
435 }
436
437 /* Returns the same values as mdamagem(). */
438 STATIC_OVL int
439 gazemm(magr, mdef, mattk)
440         register struct monst *magr, *mdef;
441         struct attack *mattk;
442 {
443         char buf[BUFSZ];
444
445         if(vis) {
446                 Sprintf(buf,"%s gazes at", Monnam(magr));
447                 pline("%s %s...", buf, mon_nam(mdef));
448         }
449
450         if (magr->mcan || !magr->mcansee ||
451             (magr->minvis && !perceives(mdef->data)) ||
452             !mdef->mcansee || mdef->msleeping) {
453             if(vis) pline("but nothing happens.");
454             return(MM_MISS);
455         }
456         /* call mon_reflects 2x, first test, then, if visible, print message */
457         if (magr->data == &mons[PM_MEDUSA] && mon_reflects(mdef, (char *)0)) {
458             if (canseemon(mdef))
459                 (void) mon_reflects(mdef,
460                                     "The gaze is reflected away by %s %s.");
461             if (mdef->mcansee) {
462                 if (mon_reflects(magr, (char *)0)) {
463                     if (canseemon(magr))
464                         (void) mon_reflects(magr,
465                                         "The gaze is reflected away by %s %s.");
466                     return (MM_MISS);
467                 }
468                 if (mdef->minvis && !perceives(magr->data)) {
469                     if (canseemon(magr)) {
470                         pline("%s doesn't seem to notice that %s gaze was reflected.",
471                               Monnam(magr), mhis(magr));
472                     }
473                     return (MM_MISS);
474                 }
475                 if (canseemon(magr))
476                     pline("%s is turned to stone!", Monnam(magr));
477                 monstone(magr);
478                 if (magr->mhp > 0) return (MM_MISS);
479                 return (MM_AGR_DIED);
480             }
481         }
482
483         return(mdamagem(magr, mdef, mattk));
484 }
485
486 /* Returns the same values as mattackm(). */
487 STATIC_OVL int
488 gulpmm(magr, mdef, mattk)
489         register struct monst *magr, *mdef;
490         register struct attack *mattk;
491 {
492         xchar   ax, ay, dx, dy;
493         int     status;
494         char buf[BUFSZ];
495         struct obj *obj;
496
497         if (mdef->data->msize >= MZ_HUGE) return MM_MISS;
498
499         if (vis) {
500                 Sprintf(buf,"%s swallows", Monnam(magr));
501                 pline("%s %s.", buf, mon_nam(mdef));
502         }
503         for (obj = mdef->minvent; obj; obj = obj->nobj)
504             (void) snuff_lit(obj);
505
506         /*
507          *  All of this maniuplation is needed to keep the display correct.
508          *  There is a flush at the next pline().
509          */
510         ax = magr->mx;
511         ay = magr->my;
512         dx = mdef->mx;
513         dy = mdef->my;
514         /*
515          *  Leave the defender in the monster chain at it's current position,
516          *  but don't leave it on the screen.  Move the agressor to the def-
517          *  ender's position.
518          */
519         remove_monster(ax, ay);
520         place_monster(magr, dx, dy);
521         newsym(ax,ay);                  /* erase old position */
522         newsym(dx,dy);                  /* update new position */
523
524         status = mdamagem(magr, mdef, mattk);
525
526         if ((status & MM_AGR_DIED) && (status & MM_DEF_DIED)) {
527             ;                                   /* both died -- do nothing  */
528         }
529         else if (status & MM_DEF_DIED) {        /* defender died */
530             /*
531              *  Note:  remove_monster() was called in relmon(), wiping out
532              *  magr from level.monsters[mdef->mx][mdef->my].  We need to
533              *  put it back and display it.     -kd
534              */
535             place_monster(magr, dx, dy);
536             newsym(dx, dy);
537         }
538         else if (status & MM_AGR_DIED) {        /* agressor died */
539             place_monster(mdef, dx, dy);
540             newsym(dx, dy);
541         }
542         else {                                  /* both alive, put them back */
543             if (cansee(dx, dy))
544                 pline("%s is regurgitated!", Monnam(mdef));
545
546             place_monster(magr, ax, ay);
547             place_monster(mdef, dx, dy);
548             newsym(ax, ay);
549             newsym(dx, dy);
550         }
551
552         return status;
553 }
554
555 STATIC_OVL int
556 explmm(magr, mdef, mattk)
557         register struct monst *magr, *mdef;
558         register struct attack *mattk;
559 {
560         int result;
561
562         if (magr->mcan)
563             return MM_MISS;
564
565         if(cansee(magr->mx, magr->my))
566                 pline("%s explodes!", Monnam(magr));
567         else    noises(magr, mattk);
568
569         result = mdamagem(magr, mdef, mattk);
570
571         /* Kill off agressor if it didn't die. */
572         if (!(result & MM_AGR_DIED)) {
573             mondead(magr);
574             if (magr->mhp > 0) return result;   /* life saved */
575             result |= MM_AGR_DIED;
576         }
577         if (magr->mtame)        /* give this one even if it was visible */
578             You(brief_feeling, "melancholy");
579
580         return result;
581 }
582
583 /*
584  *  See comment at top of mattackm(), for return values.
585  */
586 STATIC_OVL int
587 mdamagem(magr, mdef, mattk)
588         register struct monst   *magr, *mdef;
589         register struct attack  *mattk;
590 {
591         struct obj *obj;
592         char buf[BUFSZ];
593         struct permonst *pa = magr->data, *pd = mdef->data;
594         int armpro, num, tmp = d((int)mattk->damn, (int)mattk->damd);
595         boolean cancelled;
596
597         if (touch_petrifies(pd) && !resists_ston(magr)) {
598             long protector = attk_protection((int)mattk->aatyp),
599                  wornitems = magr->misc_worn_check;
600
601             /* wielded weapon gives same protection as gloves here */
602             if (otmp != 0) wornitems |= W_ARMG;
603
604             if (protector == 0L ||
605                   (protector != ~0L && (wornitems & protector) != protector)) {
606                 if (poly_when_stoned(pa)) {
607                     mon_to_stone(magr);
608                     return MM_HIT; /* no damage during the polymorph */
609                 }
610                 if (vis) pline("%s turns to stone!", Monnam(magr));
611                 monstone(magr);
612                 if (magr->mhp > 0) return 0;
613                 else if (magr->mtame && !vis)
614                     You(brief_feeling, "peculiarly sad");
615                 return MM_AGR_DIED;
616             }
617         }
618
619         /* cancellation factor is the same as when attacking the hero */
620         armpro = magic_negation(mdef);
621         cancelled = magr->mcan || !((rn2(3) >= armpro) || !rn2(50));
622
623         switch(mattk->adtyp) {
624             case AD_DGST:
625                 /* eating a Rider or its corpse is fatal */
626                 if (is_rider(mdef->data)) {
627                     if (vis)
628                         pline("%s %s!", Monnam(magr),
629                               mdef->data == &mons[PM_FAMINE] ?
630                                 "belches feebly, shrivels up and dies" :
631                               mdef->data == &mons[PM_PESTILENCE] ?
632                                 "coughs spasmodically and collapses" :
633                                 "vomits violently and drops dead");
634                     mondied(magr);
635                     if (magr->mhp > 0) return 0;        /* lifesaved */
636                     else if (magr->mtame && !vis)
637                         You(brief_feeling, "queasy");
638                     return MM_AGR_DIED;
639                 }
640                 if(flags.verbose && flags.soundok) verbalize("Burrrrp!");
641                 tmp = mdef->mhp;
642                 /* Use up amulet of life saving */
643                 if (!!(obj = mlifesaver(mdef))) m_useup(mdef, obj);
644
645                 /* Is a corpse for nutrition possible?  It may kill magr */
646                 if (!corpse_chance(mdef, magr, TRUE) || magr->mhp < 1)
647                     break;
648
649                 /* Pets get nutrition from swallowing monster whole.
650                  * No nutrition from G_NOCORPSE monster, eg, undead.
651                  * DGST monsters don't die from undead corpses
652                  */
653                 num = monsndx(mdef->data);
654                 if (magr->mtame && !magr->isminion &&
655                     !(mvitals[num].mvflags & G_NOCORPSE)) {
656                     struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE);
657                     int nutrit;
658
659                     virtualcorpse->corpsenm = num;
660                     virtualcorpse->owt = weight(virtualcorpse);
661                     nutrit = dog_nutrition(magr, virtualcorpse);
662                     dealloc_obj(virtualcorpse);
663
664                     /* only 50% nutrition, 25% of normal eating time */
665                     if (magr->meating > 1) magr->meating = (magr->meating+3)/4;
666                     if (nutrit > 1) nutrit /= 2;
667                     EDOG(magr)->hungrytime += nutrit;
668                 }
669                 break;
670             case AD_STUN:
671                 if (magr->mcan) break;
672                 if (canseemon(mdef))
673                     pline("%s %s for a moment.", Monnam(mdef),
674                           makeplural(stagger(mdef->data, "stagger")));
675                 mdef->mstun = 1;
676                 goto physical;
677             case AD_LEGS:
678                 if (magr->mcan) {
679                     tmp = 0;
680                     break;
681                 }
682                 goto physical;
683             case AD_WERE:
684             case AD_HEAL:
685             case AD_PHYS:
686  physical:
687                 if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
688                     tmp = 0;
689                 } else if(mattk->aatyp == AT_WEAP) {
690                     if(otmp) {
691                         if (otmp->otyp == CORPSE &&
692                                 touch_petrifies(&mons[otmp->corpsenm]))
693                             goto do_stone;
694                         tmp += dmgval(otmp, mdef);
695                         if (otmp->oartifact) {
696                             (void)artifact_hit(magr,mdef, otmp, &tmp, dieroll);
697                             if (mdef->mhp <= 0)
698                                 return (MM_DEF_DIED |
699                                         (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
700                         }
701                         if (tmp)
702                                 mrustm(magr, mdef, otmp);
703                     }
704                 } else if (magr->data == &mons[PM_PURPLE_WORM] &&
705                             mdef->data == &mons[PM_SHRIEKER]) {
706                     /* hack to enhance mm_aggression(); we don't want purple
707                        worm's bite attack to kill a shrieker because then it
708                        won't swallow the corpse; but if the target survives,
709                        the subsequent engulf attack should accomplish that */
710                     if (tmp >= mdef->mhp) tmp = mdef->mhp - 1;
711                 }
712                 break;
713             case AD_FIRE:
714                 if (cancelled) {
715                     tmp = 0;
716                     break;
717                 }
718                 if (vis)
719                     pline("%s is %s!", Monnam(mdef),
720                           on_fire(mdef->data, mattk));
721                 if (pd == &mons[PM_STRAW_GOLEM] ||
722                     pd == &mons[PM_PAPER_GOLEM]) {
723                         if (vis) pline("%s burns completely!", Monnam(mdef));
724                         mondied(mdef);
725                         if (mdef->mhp > 0) return 0;
726                         else if (mdef->mtame && !vis)
727                             pline("May %s roast in peace.", mon_nam(mdef));
728                         return (MM_DEF_DIED | (grow_up(magr,mdef) ?
729                                                         0 : MM_AGR_DIED));
730                 }
731                 tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
732                 tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
733                 if (resists_fire(mdef)) {
734                     if (vis)
735                         pline_The("fire doesn't seem to burn %s!",
736                                                                 mon_nam(mdef));
737                     shieldeff(mdef->mx, mdef->my);
738                     golemeffects(mdef, AD_FIRE, tmp);
739                     tmp = 0;
740                 }
741                 /* only potions damage resistant players in destroy_item */
742                 tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
743                 break;
744             case AD_COLD:
745                 if (cancelled) {
746                     tmp = 0;
747                     break;
748                 }
749                 if (vis) pline("%s is covered in frost!", Monnam(mdef));
750                 if (resists_cold(mdef)) {
751                     if (vis)
752                         pline_The("frost doesn't seem to chill %s!",
753                                                                 mon_nam(mdef));
754                     shieldeff(mdef->mx, mdef->my);
755                     golemeffects(mdef, AD_COLD, tmp);
756                     tmp = 0;
757                 }
758                 tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
759                 break;
760             case AD_ELEC:
761                 if (cancelled) {
762                     tmp = 0;
763                     break;
764                 }
765                 if (vis) pline("%s gets zapped!", Monnam(mdef));
766                 tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
767                 if (resists_elec(mdef)) {
768                     if (vis) pline_The("zap doesn't shock %s!", mon_nam(mdef));
769                     shieldeff(mdef->mx, mdef->my);
770                     golemeffects(mdef, AD_ELEC, tmp);
771                     tmp = 0;
772                 }
773                 /* only rings damage resistant players in destroy_item */
774                 tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
775                 break;
776             case AD_ACID:
777                 if (magr->mcan) {
778                     tmp = 0;
779                     break;
780                 }
781                 if (resists_acid(mdef)) {
782                     if (vis)
783                         pline("%s is covered in acid, but it seems harmless.",
784                               Monnam(mdef));
785                     tmp = 0;
786                 } else if (vis) {
787                     pline("%s is covered in acid!", Monnam(mdef));
788                     pline("It burns %s!", mon_nam(mdef));
789                 }
790                 if (!rn2(30)) erode_armor(mdef, TRUE);
791                 if (!rn2(6)) erode_obj(MON_WEP(mdef), TRUE, TRUE);
792                 break;
793             case AD_RUST:
794                 if (magr->mcan) break;
795                 if (pd == &mons[PM_IRON_GOLEM]) {
796                         if (vis) pline("%s falls to pieces!", Monnam(mdef));
797                         mondied(mdef);
798                         if (mdef->mhp > 0) return 0;
799                         else if (mdef->mtame && !vis)
800                             pline("May %s rust in peace.", mon_nam(mdef));
801                         return (MM_DEF_DIED | (grow_up(magr,mdef) ?
802                                                         0 : MM_AGR_DIED));
803                 }
804                 hurtmarmor(mdef, AD_RUST);
805                 mdef->mstrategy &= ~STRAT_WAITFORU;
806                 tmp = 0;
807                 break;
808             case AD_CORR:
809                 if (magr->mcan) break;
810                 hurtmarmor(mdef, AD_CORR);
811                 mdef->mstrategy &= ~STRAT_WAITFORU;
812                 tmp = 0;
813                 break;
814             case AD_DCAY:
815                 if (magr->mcan) break;
816                 if (pd == &mons[PM_WOOD_GOLEM] ||
817                     pd == &mons[PM_LEATHER_GOLEM]) {
818                         if (vis) pline("%s falls to pieces!", Monnam(mdef));
819                         mondied(mdef);
820                         if (mdef->mhp > 0) return 0;
821                         else if (mdef->mtame && !vis)
822                             pline("May %s rot in peace.", mon_nam(mdef));
823                         return (MM_DEF_DIED | (grow_up(magr,mdef) ?
824                                                         0 : MM_AGR_DIED));
825                 }
826                 hurtmarmor(mdef, AD_DCAY);
827                 mdef->mstrategy &= ~STRAT_WAITFORU;
828                 tmp = 0;
829                 break;
830             case AD_STON:
831                 if (magr->mcan) break;
832  do_stone:
833                 /* may die from the acid if it eats a stone-curing corpse */
834                 if (munstone(mdef, FALSE)) goto post_stone;
835                 if (poly_when_stoned(pd)) {
836                         mon_to_stone(mdef);
837                         tmp = 0;
838                         break;
839                 }
840                 if (!resists_ston(mdef)) {
841                         if (vis) pline("%s turns to stone!", Monnam(mdef));
842                         monstone(mdef);
843  post_stone:            if (mdef->mhp > 0) return 0;
844                         else if (mdef->mtame && !vis)
845                             You(brief_feeling, "peculiarly sad");
846                         return (MM_DEF_DIED | (grow_up(magr,mdef) ?
847                                                         0 : MM_AGR_DIED));
848                 }
849                 tmp = (mattk->adtyp == AD_STON ? 0 : 1);
850                 break;
851             case AD_TLPT:
852                 if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) {
853                     char mdef_Monnam[BUFSZ];
854                     /* save the name before monster teleports, otherwise
855                        we'll get "it" in the suddenly disappears message */
856                     if (vis) Strcpy(mdef_Monnam, Monnam(mdef));
857                     mdef->mstrategy &= ~STRAT_WAITFORU;
858                     (void) rloc(mdef, FALSE);
859                     if (vis && !canspotmon(mdef)
860 #ifdef STEED
861                         && mdef != u.usteed
862 #endif
863                         )
864                         pline("%s suddenly disappears!", mdef_Monnam);
865                 }
866                 break;
867             case AD_SLEE:
868                 if (!cancelled && !mdef->msleeping &&
869                         sleep_monst(mdef, rnd(10), -1)) {
870                     if (vis) {
871                         Strcpy(buf, Monnam(mdef));
872                         pline("%s is put to sleep by %s.", buf, mon_nam(magr));
873                     }
874                     mdef->mstrategy &= ~STRAT_WAITFORU;
875                     slept_monst(mdef);
876                 }
877                 break;
878             case AD_PLYS:
879                 if(!cancelled && mdef->mcanmove) {
880                     if (vis) {
881                         Strcpy(buf, Monnam(mdef));
882                         pline("%s is frozen by %s.", buf, mon_nam(magr));
883                     }
884                     mdef->mcanmove = 0;
885                     mdef->mfrozen = rnd(10);
886                     mdef->mstrategy &= ~STRAT_WAITFORU;
887                 }
888                 break;
889             case AD_SLOW:
890                 if (!cancelled && mdef->mspeed != MSLOW) {
891                     unsigned int oldspeed = mdef->mspeed;
892
893                     mon_adjust_speed(mdef, -1, (struct obj *)0);
894                     mdef->mstrategy &= ~STRAT_WAITFORU;
895                     if (mdef->mspeed != oldspeed && vis)
896                         pline("%s slows down.", Monnam(mdef));
897                 }
898                 break;
899             case AD_CONF:
900                 /* Since confusing another monster doesn't have a real time
901                  * limit, setting spec_used would not really be right (though
902                  * we still should check for it).
903                  */
904                 if (!magr->mcan && !mdef->mconf && !magr->mspec_used) {
905                     if (vis) pline("%s looks confused.", Monnam(mdef));
906                     mdef->mconf = 1;
907                     mdef->mstrategy &= ~STRAT_WAITFORU;
908                 }
909                 break;
910             case AD_BLND:
911                 if (can_blnd(magr, mdef, mattk->aatyp, (struct obj*)0)) {
912                     register unsigned rnd_tmp;
913
914                     if (vis && mdef->mcansee)
915                         pline("%s is blinded.", Monnam(mdef));
916                     rnd_tmp = d((int)mattk->damn, (int)mattk->damd);
917                     if ((rnd_tmp += mdef->mblinded) > 127) rnd_tmp = 127;
918                     mdef->mblinded = rnd_tmp;
919                     mdef->mcansee = 0;
920                     mdef->mstrategy &= ~STRAT_WAITFORU;
921                 }
922                 tmp = 0;
923                 break;
924             case AD_HALU:
925                 if (!magr->mcan && haseyes(pd) && mdef->mcansee) {
926                     if (vis) pline("%s looks %sconfused.",
927                                     Monnam(mdef), mdef->mconf ? "more " : "");
928                     mdef->mconf = 1;
929                     mdef->mstrategy &= ~STRAT_WAITFORU;
930                 }
931                 tmp = 0;
932                 break;
933             case AD_CURS:
934                 if (!night() && (pa == &mons[PM_GREMLIN])) break;
935                 if (!magr->mcan && !rn2(10)) {
936                     mdef->mcan = 1;     /* cancelled regardless of lifesave */
937                     mdef->mstrategy &= ~STRAT_WAITFORU;
938                     if (is_were(pd) && pd->mlet != S_HUMAN)
939                         were_change(mdef);
940                     if (pd == &mons[PM_CLAY_GOLEM]) {
941                             if (vis) {
942                                 pline("Some writing vanishes from %s head!",
943                                     s_suffix(mon_nam(mdef)));
944                                 pline("%s is destroyed!", Monnam(mdef));
945                             }
946                             mondied(mdef);
947                             if (mdef->mhp > 0) return 0;
948                             else if (mdef->mtame && !vis)
949                                 You(brief_feeling, "strangely sad");
950                             return (MM_DEF_DIED | (grow_up(magr,mdef) ?
951                                                         0 : MM_AGR_DIED));
952                     }
953                     if (flags.soundok) {
954                             if (!vis) You_hear("laughter.");
955                             else pline("%s chuckles.", Monnam(magr));
956                     }
957                 }
958                 break;
959             case AD_SGLD:
960                 tmp = 0;
961 #ifndef GOLDOBJ
962                 if (magr->mcan || !mdef->mgold) break;
963                 /* technically incorrect; no check for stealing gold from
964                  * between mdef's feet...
965                  */
966                 magr->mgold += mdef->mgold;
967                 mdef->mgold = 0;
968 #else
969                 if (magr->mcan) break;
970                 /* technically incorrect; no check for stealing gold from
971                  * between mdef's feet...
972                  */
973                 {
974                     struct obj *gold = findgold(mdef->minvent);
975                     if (!gold) break;
976                     obj_extract_self(gold);
977                     add_to_minv(magr, gold);
978                 }
979 #endif
980                 mdef->mstrategy &= ~STRAT_WAITFORU;
981                 if (vis) {
982                     Strcpy(buf, Monnam(magr));
983                     pline("%s steals some gold from %s.", buf, mon_nam(mdef));
984                 }
985                 if (!tele_restrict(magr)) {
986                     (void) rloc(magr, FALSE);
987                     if (vis && !canspotmon(magr))
988                         pline("%s suddenly disappears!", buf);
989                 }
990                 break;
991             case AD_DRLI:
992                 if (!cancelled && !rn2(3) && !resists_drli(mdef)) {
993                         tmp = d(2,6);
994                         if (vis)
995                             pline("%s suddenly seems weaker!", Monnam(mdef));
996                         mdef->mhpmax -= tmp;
997                         if (mdef->m_lev == 0)
998                                 tmp = mdef->mhp;
999                         else mdef->m_lev--;
1000                         /* Automatic kill if drained past level 0 */
1001                 }
1002                 break;
1003 #ifdef SEDUCE
1004             case AD_SSEX:
1005 #endif
1006             case AD_SITM:       /* for now these are the same */
1007             case AD_SEDU:
1008                 if (magr->mcan) break;
1009                 /* find an object to steal, non-cursed if magr is tame */
1010                 for (obj = mdef->minvent; obj; obj = obj->nobj)
1011                     if (!magr->mtame || !obj->cursed)
1012                         break;
1013
1014                 if (obj) {
1015                         char onambuf[BUFSZ], mdefnambuf[BUFSZ];
1016
1017                         /* make a special x_monnam() call that never omits
1018                            the saddle, and save it for later messages */
1019                         Strcpy(mdefnambuf, x_monnam(mdef, ARTICLE_THE, (char *)0, 0, FALSE));
1020
1021                         otmp = obj;
1022 #ifdef STEED
1023                         if (u.usteed == mdef &&
1024                                         otmp == which_armor(mdef, W_SADDLE))
1025                                 /* "You can no longer ride <steed>." */
1026                                 dismount_steed(DISMOUNT_POLY);
1027 #endif
1028                         obj_extract_self(otmp);
1029                         if (otmp->owornmask) {
1030                                 mdef->misc_worn_check &= ~otmp->owornmask;
1031                                 if (otmp->owornmask & W_WEP)
1032                                     setmnotwielded(mdef,otmp);
1033                                 otmp->owornmask = 0L;
1034                                 update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
1035                         }
1036                         /* add_to_minv() might free otmp [if it merges] */
1037                         if (vis)
1038                                 Strcpy(onambuf, doname(otmp));
1039                         (void) add_to_minv(magr, otmp);
1040                         if (vis) {
1041                                 Strcpy(buf, Monnam(magr));
1042                                 pline("%s steals %s from %s!", buf,
1043                                     onambuf, mdefnambuf);
1044                         }
1045                         possibly_unwield(mdef, FALSE);
1046                         mdef->mstrategy &= ~STRAT_WAITFORU;
1047                         mselftouch(mdef, (const char *)0, FALSE);
1048                         if (mdef->mhp <= 0)
1049                                 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
1050                                                         0 : MM_AGR_DIED));
1051                         if (magr->data->mlet == S_NYMPH &&
1052                             !tele_restrict(magr)) {
1053                             (void) rloc(magr, FALSE);
1054                             if (vis && !canspotmon(magr))
1055                                 pline("%s suddenly disappears!", buf);
1056                         }
1057                 }
1058                 tmp = 0;
1059                 break;
1060             case AD_DRST:
1061             case AD_DRDX:
1062             case AD_DRCO:
1063                 if (!cancelled && !rn2(8)) {
1064                     if (vis)
1065                         pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
1066                               mpoisons_subj(magr, mattk));
1067                     if (resists_poison(mdef)) {
1068                         if (vis)
1069                             pline_The("poison doesn't seem to affect %s.",
1070                                 mon_nam(mdef));
1071                     } else {
1072                         if (rn2(10)) tmp += rn1(10,6);
1073                         else {
1074                             if (vis) pline_The("poison was deadly...");
1075                             tmp = mdef->mhp;
1076                         }
1077                     }
1078                 }
1079                 break;
1080             case AD_DRIN:
1081                 if (notonhead || !has_head(pd)) {
1082                     if (vis) pline("%s doesn't seem harmed.", Monnam(mdef));
1083                     /* Not clear what to do for green slimes */
1084                     tmp = 0;
1085                     break;
1086                 }
1087                 if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) {
1088                     if (vis) {
1089                         Strcpy(buf, s_suffix(Monnam(mdef)));
1090                         pline("%s helmet blocks %s attack to %s head.",
1091                                 buf, s_suffix(mon_nam(magr)),
1092                                 mhis(mdef));
1093                     }
1094                     break;
1095                 }
1096                 if (vis) pline("%s brain is eaten!", s_suffix(Monnam(mdef)));
1097                 if (mindless(pd)) {
1098                     if (vis) pline("%s doesn't notice.", Monnam(mdef));
1099                     break;
1100                 }
1101                 tmp += rnd(10); /* fakery, since monsters lack INT scores */
1102                 if (magr->mtame && !magr->isminion) {
1103                     EDOG(magr)->hungrytime += rnd(60);
1104                     magr->mconf = 0;
1105                 }
1106                 if (tmp >= mdef->mhp && vis)
1107                     pline("%s last thought fades away...",
1108                                   s_suffix(Monnam(mdef)));
1109                 break;
1110             case AD_SLIM:
1111                 if (cancelled) break;   /* physical damage only */
1112                 if (!rn2(4) && !flaming(mdef->data) &&
1113                                 mdef->data != &mons[PM_GREEN_SLIME]) {
1114                     (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis);
1115                     mdef->mstrategy &= ~STRAT_WAITFORU;
1116                     tmp = 0;
1117                 }
1118                 break;
1119             case AD_STCK:
1120                 if (cancelled) tmp = 0;
1121                 break;
1122             case AD_WRAP: /* monsters cannot grab one another, it's too hard */
1123                 if (magr->mcan) tmp = 0;
1124                 break;
1125             case AD_ENCH:
1126                 /* there's no msomearmor() function, so just do damage */
1127              /* if (cancelled) break; */
1128                 break;
1129             default:    tmp = 0;
1130                         break;
1131         }
1132         if(!tmp) return(MM_MISS);
1133
1134         if((mdef->mhp -= tmp) < 1) {
1135             if (m_at(mdef->mx, mdef->my) == magr) {  /* see gulpmm() */
1136                 remove_monster(mdef->mx, mdef->my);
1137                 mdef->mhp = 1;  /* otherwise place_monster will complain */
1138                 place_monster(mdef, mdef->mx, mdef->my);
1139                 mdef->mhp = 0;
1140             }
1141             monkilled(mdef, "", (int)mattk->adtyp);
1142             if (mdef->mhp > 0) return 0; /* mdef lifesaved */
1143
1144             if (mattk->adtyp == AD_DGST) {
1145                 /* various checks similar to dog_eat and meatobj.
1146                  * after monkilled() to provide better message ordering */
1147                 if (mdef->cham != CHAM_ORDINARY) {
1148                     (void) newcham(magr, (struct permonst *)0, FALSE, TRUE);
1149                 } else if (mdef->data == &mons[PM_GREEN_SLIME]) {
1150                     (void) newcham(magr, &mons[PM_GREEN_SLIME], FALSE, TRUE);
1151                 } else if (mdef->data == &mons[PM_WRAITH]) {
1152                     (void) grow_up(magr, (struct monst *)0);
1153                     /* don't grow up twice */
1154                     return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED));
1155                 } else if (mdef->data == &mons[PM_NURSE]) {
1156                     magr->mhp = magr->mhpmax;
1157                 }
1158             }
1159
1160             return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
1161         }
1162         return(MM_HIT);
1163 }
1164
1165 #endif /* OVLB */
1166
1167
1168 #ifdef OVL0
1169
1170 int
1171 noattacks(ptr)                  /* returns 1 if monster doesn't attack */
1172         struct  permonst *ptr;
1173 {
1174         int i;
1175
1176         for(i = 0; i < NATTK; i++)
1177                 if(ptr->mattk[i].aatyp) return(0);
1178
1179         return(1);
1180 }
1181
1182 /* `mon' is hit by a sleep attack; return 1 if it's affected, 0 otherwise */
1183 int
1184 sleep_monst(mon, amt, how)
1185 struct monst *mon;
1186 int amt, how;
1187 {
1188         if (resists_sleep(mon) ||
1189                 (how >= 0 && resist(mon, (char)how, 0, NOTELL))) {
1190             shieldeff(mon->mx, mon->my);
1191         } else if (mon->mcanmove) {
1192             amt += (int) mon->mfrozen;
1193             if (amt > 0) {      /* sleep for N turns */
1194                 mon->mcanmove = 0;
1195                 mon->mfrozen = min(amt, 127);
1196             } else {            /* sleep until awakened */
1197                 mon->msleeping = 1;
1198             }
1199             return 1;
1200         }
1201         return 0;
1202 }
1203
1204 /* sleeping grabber releases, engulfer doesn't; don't use for paralysis! */
1205 void
1206 slept_monst(mon)
1207 struct monst *mon;
1208 {
1209         if ((mon->msleeping || !mon->mcanmove) && mon == u.ustuck &&
1210                 !sticks(youmonst.data) && !u.uswallow) {
1211             pline("%s grip relaxes.", s_suffix(Monnam(mon)));
1212             unstuck(mon);
1213         }
1214 }
1215
1216 #endif /* OVL0 */
1217 #ifdef OVLB
1218
1219 STATIC_OVL void
1220 mrustm(magr, mdef, obj)
1221 register struct monst *magr, *mdef;
1222 register struct obj *obj;
1223 {
1224         boolean is_acid;
1225
1226         if (!magr || !mdef || !obj) return; /* just in case */
1227
1228         if (dmgtype(mdef->data, AD_CORR))
1229             is_acid = TRUE;
1230         else if (dmgtype(mdef->data, AD_RUST))
1231             is_acid = FALSE;
1232         else
1233             return;
1234
1235         if (!mdef->mcan &&
1236             (is_acid ? is_corrodeable(obj) : is_rustprone(obj)) &&
1237             (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) {
1238                 if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) {
1239                     if (cansee(mdef->mx, mdef->my) && flags.verbose)
1240                         pline("%s weapon is not affected.",
1241                                          s_suffix(Monnam(magr)));
1242                     if (obj->greased && !rn2(2)) obj->greased = 0;
1243                 } else {
1244                     if (cansee(mdef->mx, mdef->my)) {
1245                         pline("%s %s%s!", s_suffix(Monnam(magr)),
1246                             aobjnam(obj, (is_acid ? "corrode" : "rust")),
1247                             (is_acid ? obj->oeroded2 : obj->oeroded)
1248                                 ? " further" : "");
1249                     }
1250                     if (is_acid) obj->oeroded2++;
1251                     else obj->oeroded++;
1252                 }
1253         }
1254 }
1255
1256 STATIC_OVL void
1257 mswingsm(magr, mdef, otemp)
1258 register struct monst *magr, *mdef;
1259 register struct obj *otemp;
1260 {
1261         char buf[BUFSZ];
1262         if (!flags.verbose || Blind || !mon_visible(magr)) return;
1263         Strcpy(buf, mon_nam(mdef));
1264         pline("%s %s %s %s at %s.", Monnam(magr),
1265               (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
1266               mhis(magr), singular(otemp, xname), buf);
1267 }
1268
1269 /*
1270  * Passive responses by defenders.  Does not replicate responses already
1271  * handled above.  Returns same values as mattackm.
1272  */
1273 STATIC_OVL int
1274 passivemm(magr,mdef,mhit,mdead)
1275 register struct monst *magr, *mdef;
1276 boolean mhit;
1277 int mdead;
1278 {
1279         register struct permonst *mddat = mdef->data;
1280         register struct permonst *madat = magr->data;
1281         char buf[BUFSZ];
1282         int i, tmp;
1283
1284         for(i = 0; ; i++) {
1285             if(i >= NATTK) return (mdead | mhit); /* no passive attacks */
1286             if(mddat->mattk[i].aatyp == AT_NONE) break;
1287         }
1288         if (mddat->mattk[i].damn)
1289             tmp = d((int)mddat->mattk[i].damn,
1290                                     (int)mddat->mattk[i].damd);
1291         else if(mddat->mattk[i].damd)
1292             tmp = d((int)mddat->mlevel+1, (int)mddat->mattk[i].damd);
1293         else
1294             tmp = 0;
1295
1296         /* These affect the enemy even if defender killed */
1297         switch(mddat->mattk[i].adtyp) {
1298             case AD_ACID:
1299                 if (mhit && !rn2(2)) {
1300                     Strcpy(buf, Monnam(magr));
1301                     if(canseemon(magr))
1302                         pline("%s is splashed by %s acid!",
1303                               buf, s_suffix(mon_nam(mdef)));
1304                     if (resists_acid(magr)) {
1305                         if(canseemon(magr))
1306                             pline("%s is not affected.", Monnam(magr));
1307                         tmp = 0;
1308                     }
1309                 } else tmp = 0;
1310                 goto assess_dmg;
1311             case AD_ENCH:       /* KMH -- remove enchantment (disenchanter) */
1312                 if (mhit && !mdef->mcan && otmp) {
1313                     (void) drain_item(otmp);
1314                     /* No message */
1315                 }
1316                 break;
1317             default:
1318                 break;
1319         }
1320         if (mdead || mdef->mcan) return (mdead|mhit);
1321
1322         /* These affect the enemy only if defender is still alive */
1323         if (rn2(3)) switch(mddat->mattk[i].adtyp) {
1324             case AD_PLYS: /* Floating eye */
1325                 if (tmp > 127) tmp = 127;
1326                 if (mddat == &mons[PM_FLOATING_EYE]) {
1327                     if (!rn2(4)) tmp = 127;
1328                     if (magr->mcansee && haseyes(madat) && mdef->mcansee &&
1329                         (perceives(madat) || !mdef->minvis)) {
1330                         Sprintf(buf, "%s gaze is reflected by %%s %%s.",
1331                                 s_suffix(mon_nam(mdef)));
1332                         if (mon_reflects(magr,
1333                                          canseemon(magr) ? buf : (char *)0))
1334                                 return(mdead|mhit);
1335                         Strcpy(buf, Monnam(magr));
1336                         if(canseemon(magr))
1337                             pline("%s is frozen by %s gaze!",
1338                                   buf, s_suffix(mon_nam(mdef)));
1339                         magr->mcanmove = 0;
1340                         magr->mfrozen = tmp;
1341                         return (mdead|mhit);
1342                     }
1343                 } else { /* gelatinous cube */
1344                     Strcpy(buf, Monnam(magr));
1345                     if(canseemon(magr))
1346                         pline("%s is frozen by %s.", buf, mon_nam(mdef));
1347                     magr->mcanmove = 0;
1348                     magr->mfrozen = tmp;
1349                     return (mdead|mhit);
1350                 }
1351                 return 1;
1352             case AD_COLD:
1353                 if (resists_cold(magr)) {
1354                     if (canseemon(magr)) {
1355                         pline("%s is mildly chilly.", Monnam(magr));
1356                         golemeffects(magr, AD_COLD, tmp);
1357                     }
1358                     tmp = 0;
1359                     break;
1360                 }
1361                 if(canseemon(magr))
1362                     pline("%s is suddenly very cold!", Monnam(magr));
1363                 mdef->mhp += tmp / 2;
1364                 if (mdef->mhpmax < mdef->mhp) mdef->mhpmax = mdef->mhp;
1365                 if (mdef->mhpmax > ((int) (mdef->m_lev+1) * 8))
1366                     (void)split_mon(mdef, magr);
1367                 break;
1368             case AD_STUN:
1369                 if (!magr->mstun) {
1370                     magr->mstun = 1;
1371                     if (canseemon(magr))
1372                         pline("%s %s...", Monnam(magr),
1373                               makeplural(stagger(magr->data, "stagger")));
1374                 }
1375                 tmp = 0;
1376                 break;
1377             case AD_FIRE:
1378                 if (resists_fire(magr)) {
1379                     if (canseemon(magr)) {
1380                         pline("%s is mildly warmed.", Monnam(magr));
1381                         golemeffects(magr, AD_FIRE, tmp);
1382                     }
1383                     tmp = 0;
1384                     break;
1385                 }
1386                 if(canseemon(magr))
1387                     pline("%s is suddenly very hot!", Monnam(magr));
1388                 break;
1389             case AD_ELEC:
1390                 if (resists_elec(magr)) {
1391                     if (canseemon(magr)) {
1392                         pline("%s is mildly tingled.", Monnam(magr));
1393                         golemeffects(magr, AD_ELEC, tmp);
1394                     }
1395                     tmp = 0;
1396                     break;
1397                 }
1398                 if(canseemon(magr))
1399                     pline("%s is jolted with electricity!", Monnam(magr));
1400                 break;
1401             default: tmp = 0;
1402                 break;
1403         }
1404         else tmp = 0;
1405
1406     assess_dmg:
1407         if((magr->mhp -= tmp) <= 0) {
1408                 monkilled(magr, "", (int)mddat->mattk[i].adtyp);
1409                 return (mdead | mhit | MM_AGR_DIED);
1410         }
1411         return (mdead | mhit);
1412 }
1413
1414 /* "aggressive defense"; what type of armor prevents specified attack
1415    from touching its target? */
1416 long
1417 attk_protection(aatyp)
1418 int aatyp;
1419 {
1420     long w_mask = 0L;
1421
1422     switch (aatyp) {
1423     case AT_NONE:
1424     case AT_SPIT:
1425     case AT_EXPL:
1426     case AT_BOOM:
1427     case AT_GAZE:
1428     case AT_BREA:
1429     case AT_MAGC:
1430         w_mask = ~0L;           /* special case; no defense needed */
1431         break;
1432     case AT_CLAW:
1433     case AT_TUCH:
1434     case AT_WEAP:
1435         w_mask = W_ARMG;        /* caller needs to check for weapon */
1436         break;
1437     case AT_KICK:
1438         w_mask = W_ARMF;
1439         break;
1440     case AT_BUTT:
1441         w_mask = W_ARMH;
1442         break;
1443     case AT_HUGS:
1444         w_mask = (W_ARMC|W_ARMG); /* attacker needs both to be protected */
1445         break;
1446     case AT_BITE:
1447     case AT_STNG:
1448     case AT_ENGL:
1449     case AT_TENT:
1450     default:
1451         w_mask = 0L;            /* no defense available */
1452         break;
1453     }
1454     return w_mask;
1455 }
1456
1457 #endif /* OVLB */
1458
1459 /*mhitm.c*/
1460