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