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