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
9extern boolean notonhead;
10
11#ifdef OVLB
12
13static NEARDATA boolean vis, far_noise;
14static NEARDATA long noisetime;
15static NEARDATA struct obj *otmp;
16
17static const char brief_feeling[] =
18	"have a %s feeling for a moment, then it passes.";
19
20STATIC_DCL char *FDECL(mon_nam_too, (char *,struct monst *,struct monst *));
21STATIC_DCL void FDECL(mrustm, (struct monst *, struct monst *, struct obj *));
22STATIC_DCL int FDECL(hitmm, (struct monst *,struct monst *,struct attack *));
23STATIC_DCL int FDECL(gazemm, (struct monst *,struct monst *,struct attack *));
24STATIC_DCL int FDECL(gulpmm, (struct monst *,struct monst *,struct attack *));
25STATIC_DCL int FDECL(explmm, (struct monst *,struct monst *,struct attack *));
26STATIC_DCL int FDECL(mdamagem, (struct monst *,struct monst *,struct attack *));
27STATIC_DCL void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *));
28STATIC_DCL void FDECL(noises,(struct monst *,struct attack *));
29STATIC_DCL void FDECL(missmm,(struct monst *,struct monst *,struct attack *));
30STATIC_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 */
36static 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 */
40STATIC_OVL char *
41mon_nam_too(outbuf, mon, other_mon)
42char *outbuf;
43struct 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
55STATIC_OVL void
56noises(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
71STATIC_OVL
72void
73missmm(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 */
105int
106fightm(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 */
194int
195mattackm(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(). */
381STATIC_OVL int
382hitmm(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(). */
438STATIC_OVL int
439gazemm(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(). */
487STATIC_OVL int
488gulpmm(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
555STATIC_OVL int
556explmm(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 */
586STATIC_OVL int
587mdamagem(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
1170int
1171noattacks(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 */
1183int
1184sleep_monst(mon, amt, how)
1185struct monst *mon;
1186int 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! */
1205void
1206slept_monst(mon)
1207struct 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
1219STATIC_OVL void
1220mrustm(magr, mdef, obj)
1221register struct monst *magr, *mdef;
1222register 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
1256STATIC_OVL void
1257mswingsm(magr, mdef, otemp)
1258register struct monst *magr, *mdef;
1259register 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 */
1273STATIC_OVL int
1274passivemm(magr,mdef,mhit,mdead)
1275register struct monst *magr, *mdef;
1276boolean mhit;
1277int 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? */
1416long
1417attk_protection(aatyp)
1418int 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
1461