1    | /*	SCCS Id: @(#)uhitm.c	3.3	2000/02/20	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | 
7    | STATIC_DCL boolean FDECL(known_hitum, (struct monst *,int *,struct attack *));
8    | STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *));
9    | STATIC_DCL boolean FDECL(hitum, (struct monst *,int,struct attack *));
10   | STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *,struct obj *,int));
11   | STATIC_DCL boolean FDECL(m_slips_free, (struct monst *mtmp,struct attack *mattk));
12   | STATIC_DCL int FDECL(explum, (struct monst *,struct attack *));
13   | STATIC_DCL void FDECL(start_engulf, (struct monst *));
14   | STATIC_DCL void NDECL(end_engulf);
15   | STATIC_DCL int FDECL(gulpum, (struct monst *,struct attack *));
16   | STATIC_DCL boolean FDECL(hmonas, (struct monst *,int));
17   | STATIC_DCL void FDECL(nohandglow, (struct monst *));
18   | 
19   | extern boolean notonhead;	/* for long worms */
20   | /* The below might become a parameter instead if we use it a lot */
21   | static int dieroll;
22   | /* Used to flag attacks caused by Stormbringer's maliciousness. */
23   | static boolean override_confirmation = FALSE;
24   | 
25   | #define PROJECTILE(obj)	((obj) && is_ammo(obj))
26   | 
27   | /* modified from hurtarmor() in mhitu.c */
28   | /* This is not static because it is also used for monsters rusting monsters */
29   | void
30   | hurtmarmor(mdef, attk)
31   | struct monst *mdef;
32   | int attk;
33   | {
34   | 	int	hurt;
35   | 	struct obj *target;
36   | 
37   | 	switch(attk) {
38   | 	    /* 0 is burning, which we should never be called with */
39   | 	    case AD_RUST: hurt = 1; break;
40   | 	    case AD_CORRODE: hurt = 3; break;
41   | 	    default: hurt = 2; break;
42   | 	}
43   | 	/* What the following code does: it keeps looping until it
44   | 	 * finds a target for the rust monster.
45   | 	 * Head, feet, etc... not covered by metal, or covered by
46   | 	 * rusty metal, are not targets.  However, your body always
47   | 	 * is, no matter what covers it.
48   | 	 */
49   | 	while (1) {
50   | 	    switch(rn2(5)) {
51   | 	    case 0:
52   | 		target = which_armor(mdef, W_ARMH);
53   | 		if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef))
54   | 		    continue;
55   | 		break;
56   | 	    case 1:
57   | 		target = which_armor(mdef, W_ARMC);
58   | 		if (target) {
59   | 		    (void)rust_dmg(target, xname(target), hurt, TRUE, mdef);
60   | 		    break;
61   | 		}
62   | 		if ((target = which_armor(mdef, W_ARM)) != (struct obj *)0) {
63   | 		    (void)rust_dmg(target, xname(target), hurt, TRUE, mdef);
64   | #ifdef TOURIST
65   | 		} else if ((target = which_armor(mdef, W_ARMU)) != (struct obj *)0) {
66   | 		    (void)rust_dmg(target, xname(target), hurt, TRUE, mdef);
67   | #endif
68   | 		}
69   | 		break;
70   | 	    case 2:
71   | 		target = which_armor(mdef, W_ARMS);
72   | 		if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef))
73   | 		    continue;
74   | 		break;
75   | 	    case 3:
76   | 		target = which_armor(mdef, W_ARMG);
77   | 		if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef))
78   | 		    continue;
79   | 		break;
80   | 	    case 4:
81   | 		target = which_armor(mdef, W_ARMF);
82   | 		if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef))
83   | 		    continue;
84   | 		break;
85   | 	    }
86   | 	    break; /* Out of while loop */
87   | 	}
88   | }
89   | 
90   | boolean
91   | attack_checks(mtmp, wep)
92   | register struct monst *mtmp;
93   | struct obj *wep;	/* uwep for attack(), null for kick_monster() */
94   | {
95   | 	char qbuf[QBUFSZ];
96   | 
97   | 	/* if you're close enough to attack, alert any waiting monster */
98   | 	mtmp->mstrategy &= ~STRAT_WAITMASK;
99   | 
100  | 	if (u.uswallow && mtmp == u.ustuck) return FALSE;
101  | 
102  | 	if (flags.forcefight) {
103  | 		/* Do this in the caller, after we checked that the monster
104  | 		 * didn't die from the blow.  Reason: putting the 'I' there
105  | 		 * causes the hero to forget the square's contents since
106  | 		 * both 'I' and remembered contents are stored in .glyph.
107  | 		 * If the monster dies immediately from the blow, the 'I' will
108  | 		 * not stay there, so the player will have suddenly forgotten
109  | 		 * the square's contents for no apparent reason.
110  | 		if (!canspotmon(mtmp) &&
111  | 		    !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph))
112  | 			map_invisible(u.ux+u.dx, u.uy+u.dy);
113  | 		 */
114  | 		return FALSE;
115  | 	}
116  | 
117  | 	/* Put up an invisible monster marker, but one exception is for
118  | 	 * monsters that hide.  That already prints a warning message and
119  | 	 * prevents you from hitting the monster just via the hidden monster
120  | 	 * code below; if we also did that here, similar behavior would be
121  | 	 * happening two turns in a row.
122  | 	 */
123  | 	if (!canspotmon(mtmp) &&
124  | 		    !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph) &&
125  | 		    !(!Blind && mtmp->mundetected && hides_under(mtmp->data))) {
126  | 		pline("Wait!  There's %s there you can't see!",
127  | 			something);
128  | 		map_invisible(u.ux+u.dx, u.uy+u.dy);
129  | 		/* if it was an invisible mimic, treat it as if we stumbled
130  | 		 * onto a visible mimic
131  | 		 */
132  | 		if(mtmp->m_ap_type && !Protection_from_shape_changers) {
133  | 		    if(!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data,AD_STCK))
134  | 			u.ustuck = mtmp;
135  | 		}
136  | 		wakeup(mtmp); /* always necessary; also un-mimics mimics */
137  | 		return TRUE;
138  | 	}
139  | 
140  | 	if(mtmp->m_ap_type && !Protection_from_shape_changers
141  | 						&& !sensemon(mtmp)) {
142  | 		/* If a hidden mimic was in a square where a player remembers
143  | 		 * some (probably different) unseen monster, the player is in
144  | 		 * luck--he attacks it even though it's hidden.
145  | 		 */
146  | 		if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) {
147  | 		    seemimic(mtmp);
148  | 		    return(FALSE);
149  | 		}
150  | 		stumble_onto_mimic(mtmp);
151  | 		return TRUE;
152  | 	}
153  | 
154  | 	if (mtmp->mundetected && !canseemon(mtmp) &&
155  | 		(hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)) {
156  | 	    mtmp->mundetected = mtmp->msleeping = 0;
157  | 	    newsym(mtmp->mx, mtmp->my);
158  | 	    if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) {
159  | 		seemimic(mtmp);
160  | 		return(FALSE);
161  | 	    }
162  | 	    if (!(Blind ? Blind_telepat : Unblind_telepat)) {
163  | 		struct obj *obj;
164  | 
165  | 		if (Blind || (is_pool(mtmp->mx,mtmp->my) && !Underwater))
166  | 		    pline("Wait!  There's a hidden monster there!");
167  | 		else if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0)
168  | 		    pline("Wait!  There's %s hiding under %s!",
169  | 			  an(l_monnam(mtmp)), doname(obj));
170  | 		return TRUE;
171  | 	    }
172  | 	}
173  | 
174  | 	if (flags.confirm && mtmp->mpeaceful
175  | 	    && !Confusion && !Hallucination && !Stunned) {
176  | 		/* Intelligent chaotic weapons (Stormbringer) want blood */
177  | 		if (wep && wep->oartifact == ART_STORMBRINGER) {
178  | 			override_confirmation = TRUE;
179  | 			return(FALSE);
180  | 		}
181  | 		if (canspotmon(mtmp)) {
182  | 			Sprintf(qbuf, "Really attack %s?", mon_nam(mtmp));
183  | 			if (yn(qbuf) != 'y') {
184  | 				flags.move = 0;
185  | 				return(TRUE);
186  | 			}
187  | 		}
188  | 	}
189  | 
190  | 	return(FALSE);
191  | }
192  | 
193  | schar
194  | find_roll_to_hit(mtmp)
195  | register struct monst *mtmp;
196  | {
197  | 	schar tmp;
198  | 	int tmp2;
199  | 
200  | 	tmp = 1 + Luck + abon() + find_mac(mtmp) + u.uhitinc +
201  | 		maybe_polyd(youmonst.data->mlevel, u.ulevel);
202  | 
203  | /*	it is unchivalrous to attack the defenseless or from behind */
204  | 	if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL &&
205  | 	    (!mtmp->mcanmove || mtmp->msleeping || mtmp->mflee) &&
206  | 	    u.ualign.record > -10) {
207  | 	    You("caitiff!");
208  | 	    adjalign(-1);
209  | 	}
210  | 
211  | /*	attacking peaceful creatures is bad for the samurai's giri */
212  | 	if (Role_if(PM_SAMURAI) && mtmp->mpeaceful &&
213  | 	    u.ualign.record > -10) {
214  | 	    You("dishonorably attack the innocent!");
215  | 	    adjalign(-1);
216  | 	}
217  | 
218  | /*	Adjust vs. (and possibly modify) monster state.		*/
219  | 
220  | 	if(mtmp->mstun) tmp += 2;
221  | 	if(mtmp->mflee) tmp += 2;
222  | 
223  | 	if (mtmp->msleeping) {
224  | 		mtmp->msleeping = 0;
225  | 		tmp += 2;
226  | 	}
227  | 	if(!mtmp->mcanmove) {
228  | 		tmp += 4;
229  | 		if(!rn2(10)) {
230  | 			mtmp->mcanmove = 1;
231  | 			mtmp->mfrozen = 0;
232  | 		}
233  | 	}
234  | 	if (is_orc(mtmp->data) && maybe_polyd(is_elf(youmonst.data),
235  | 			Race_if(PM_ELF)))
236  | 	    tmp++;
237  | 	if(Role_if(PM_MONK) && !Upolyd) {
238  | 	    if (uarm) {
239  | 		Your("armor is rather cumbersome...");
240  | 		tmp -= urole.spelarmr;
241  | 	    } else if (!uwep)
242  | 		tmp += (u.ulevel / 3) + 2;
243  | 	}
244  | 
245  | /*	with a lot of luggage, your agility diminishes */
246  | 	if ((tmp2 = near_capacity()) != 0) tmp -= (tmp2*2) - 1;
247  | 	if (u.utrap) tmp -= 3;
248  | /*	Some monsters have a combination of weapon attacks and non-weapon
249  |  *	attacks.  It is therefore wrong to add hitval to tmp; we must add
250  |  *	it only for the specific attack (in hmonas()).
251  |  */
252  | 	if (uwep && !Upolyd) {
253  | 		tmp += hitval(uwep, mtmp);
254  | 		tmp += weapon_hit_bonus(uwep);
255  | 	}
256  | 	return tmp;
257  | }
258  | 
259  | /* try to attack; return FALSE if monster evaded */
260  | /* u.dx and u.dy must be set */
261  | boolean
262  | attack(mtmp)
263  | register struct monst *mtmp;
264  | {
265  | 	schar tmp;
266  | 	register struct permonst *mdat = mtmp->data;
267  | 
268  | 	/* This section of code provides protection against accidentally
269  | 	 * hitting peaceful (like '@') and tame (like 'd') monsters.
270  | 	 * Protection is provided as long as player is not: blind, confused,
271  | 	 * hallucinating or stunned.
272  | 	 * changes by wwp 5/16/85
273  | 	 * More changes 12/90, -dkh-. if its tame and safepet, (and protected
274  | 	 * 07/92) then we assume that you're not trying to attack. Instead,
275  | 	 * you'll usually just swap places if this is a movement command
276  | 	 */
277  | 	/* Intelligent chaotic weapons (Stormbringer) want blood */
278  | 	if (is_safepet(mtmp) && !flags.forcefight) {
279  | 	    if (!uwep || uwep->oartifact != ART_STORMBRINGER) {
280  | 		/* there are some additional considerations: this won't work
281  | 		 * if in a shop or Punished or you miss a random roll or
282  | 		 * if you can walk thru walls and your pet cannot (KAA) or
283  | 		 * if your pet is a long worm (unless someone does better).
284  | 		 * there's also a chance of displacing a "frozen" monster.
285  | 		 * sleeping monsters might magically walk in their sleep.
286  | 		 */
287  | 		unsigned int foo = (Punished ||
288  | 				    !rn2(7) || is_longworm(mtmp->data));
289  | 
290  | 		if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || foo
291  | 			|| (IS_ROCK(levl[u.ux][u.uy].typ) &&
292  | 					!passes_walls(mtmp->data))) {
293  | 		    char buf[BUFSZ];
294  | 
295  | 		    mtmp->mflee = 1;
296  | 		    mtmp->mfleetim = rnd(6);
297  | 		    Strcpy(buf, y_monnam(mtmp));
298  | 		    buf[0] = highc(buf[0]);
299  | 		    You("stop.  %s is in the way!", buf);
300  | 		    return(TRUE);
301  | 		} else if ((mtmp->mfrozen || (! mtmp->mcanmove)
302  | 				|| (mtmp->data->mmove == 0)) && rn2(6)) {
303  | 		    pline("%s doesn't seem to move!", Monnam(mtmp));
304  | 		    return(TRUE);
305  | 		} else return(FALSE);
306  | 	    }
307  | 	}
308  | 
309  | 	/* possibly set in attack_checks;
310  | 	   examined in known_hitum, called via hitum or hmonas below */
311  | 	override_confirmation = FALSE;
312  | 	if (attack_checks(mtmp, uwep)) return(TRUE);
313  | 
314  | 	if (Upolyd) {
315  | 		/* certain "pacifist" monsters don't attack */
316  | 		if(noattacks(youmonst.data)) {
317  | 			You("have no way to attack monsters physically.");
318  | 			mtmp->mstrategy &= ~STRAT_WAITMASK;
319  | 			goto atk_done;
320  | 		}
321  | 	}
322  | 
323  | 	if(check_capacity("You cannot fight while so heavily loaded."))
324  | 	    goto atk_done;
325  | 
326  | 	if (u.twoweap && !can_twoweapon())
327  | 		untwoweapon();
328  | 
329  | 	if(unweapon) {
330  | 	    unweapon = FALSE;
331  | 	    if(flags.verbose) {
332  | 		if(uwep)
333  | 		    You("begin bashing monsters with your %s.",
334  | 			aobjnam(uwep, (char *)0));
335  | 		else if (!cantwield(youmonst.data))
336  | 		    You("begin %sing monsters with your %s %s.",
337  | 			Role_if(PM_MONK) ? "strik" : "bash",
338  | 			uarmg ? "gloved" : "bare",	/* Del Lamb */
339  | 			makeplural(body_part(HAND)));
340  | 	    }
341  | 	}
342  | 	exercise(A_STR, TRUE);		/* you're exercising muscles */
343  | 	/* andrew@orca: prevent unlimited pick-axe attacks */
344  | 	u_wipe_engr(3);
345  | 
346  | 	/* Is the "it died" check actually correct? */
347  | 	if(mdat->mlet == S_LEPRECHAUN && !mtmp->mfrozen && !mtmp->msleeping &&
348  | 	   !mtmp->mconf && mtmp->mcansee && !rn2(7) &&
349  | 	   (m_move(mtmp, 0) == 2 ||			    /* it died */
350  | 	   mtmp->mx != u.ux+u.dx || mtmp->my != u.uy+u.dy)) /* it moved */
351  | 		return(FALSE);
352  | 
353  | 	tmp = find_roll_to_hit(mtmp);
354  | 	if (Upolyd)
355  | 		(void) hmonas(mtmp, tmp);
356  | 	else
357  | 		(void) hitum(mtmp, tmp, youmonst.data->mattk);
358  | 	mtmp->mstrategy &= ~STRAT_WAITMASK;
359  | 
360  | atk_done:
361  | 	/* see comment in attack_checks() */
362  | 	/* we only need to check for this if we did an attack_checks()
363  | 	 * and it returned 0 (it's okay to attack), and the monster didn't
364  | 	 * evade.
365  | 	 */
366  | 	if (flags.forcefight && mtmp->mhp > 0 && !canspotmon(mtmp) &&
367  | 	    !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph) &&
368  | 	    !(u.uswallow && mtmp == u.ustuck))
369  | 		map_invisible(u.ux+u.dx, u.uy+u.dy);
370  | 
371  | 	return(TRUE);
372  | }
373  | 
374  | STATIC_OVL boolean
375  | known_hitum(mon, mhit, uattk)	/* returns TRUE if monster still lives */
376  | register struct monst *mon;
377  | register int *mhit;
378  | struct attack *uattk;
379  | {
380  | 	register boolean malive = TRUE;
381  | 
382  | 	if (override_confirmation) {
383  | 	    /* this may need to be generalized if weapons other than
384  | 	       Stormbringer acquire similar anti-social behavior... */
385  | 	    if (flags.verbose) Your("bloodthirsty blade attacks!");
386  | 	}
387  | 
388  | 	if(!*mhit) {
389  | 	    missum(mon, uattk);
390  | 	} else {
391  | 	    int oldhp = mon->mhp;
392  | 
393  | 		/* KMH, conduct */
394  | 		if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))
395  | 		    u.uconduct.weaphit++;
396  | 
397  | 	    /* we hit the monster; be careful: it might die! */
398  | 	    notonhead = (mon->mx != u.ux+u.dx || mon->my != u.uy+u.dy);
399  | 	    malive = hmon(mon, uwep, 0);
400  | 	    if (malive && u.twoweap) malive = hmon(mon, uswapwep, 0);
401  | 	    if (malive) {
402  | 		/* monster still alive */
403  | 		if(!rn2(25) && mon->mhp < mon->mhpmax/2
404  | 			    && !(u.uswallow && mon == u.ustuck)) {
405  | 		    /* maybe should regurgitate if swallowed? */
406  | 		    mon->mflee = 1;
407  | 		    if(!rn2(3)) {
408  | 			mon->mfleetim = rnd(100);
409  | 			if (!Blind) pline("%s turns to flee!", (Monnam(mon)));
410  | 		    }
411  | 		    if(u.ustuck == mon && !u.uswallow && !sticks(youmonst.data))
412  | 			u.ustuck = 0;
413  | 		}
414  | 		/* Vorpal Blade hit converted to miss */
415  | 		/* could be headless monster or worm tail */
416  | 		if (mon->mhp == oldhp)
417  | 			*mhit = 0;
418  | 		if (mon->wormno && *mhit)
419  | 			cutworm(mon, u.ux+u.dx, u.uy+u.dy, uwep);
420  | 	    }
421  | 	}
422  | 	return(malive);
423  | }
424  | 
425  | STATIC_OVL boolean
426  | hitum(mon, tmp, uattk)		/* returns TRUE if monster still lives */
427  | struct monst *mon;
428  | int tmp;
429  | struct attack *uattk;
430  | {
431  | 	boolean malive;
432  | 	int mhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
433  | 
434  | 	if(tmp > dieroll) exercise(A_DEX, TRUE);
435  | 	malive = known_hitum(mon, &mhit, uattk);
436  | 	(void) passive(mon, mhit, malive, AT_WEAP);
437  | 	return(malive);
438  | }
439  | 
440  | boolean			/* general "damage monster" routine */
441  | hmon(mon, obj, thrown)		/* return TRUE if mon still alive */
442  | struct monst *mon;
443  | struct obj *obj;
444  | int thrown;
445  | {
446  | 	boolean result, anger_guards;
447  | 
448  | 	anger_guards = (mon->mpeaceful &&
449  | 			    (mon->ispriest || mon->isshk ||
450  | 			     mon->data == &mons[PM_WATCHMAN] ||
451  | 			     mon->data == &mons[PM_WATCH_CAPTAIN]));
452  | 	result = hmon_hitmon(mon, obj, thrown);
453  | 	if (mon->ispriest && !rn2(2)) ghod_hitsu(mon);
454  | 	if (anger_guards) (void)angry_guards(!flags.soundok);
455  | 	return result;
456  | }
457  | 
458  | /* guts of hmon() */
459  | STATIC_OVL boolean
460  | hmon_hitmon(mon, obj, thrown)
461  | struct monst *mon;
462  | struct obj *obj;
463  | int thrown;
464  | {
465  | 	int tmp;
466  | 	struct permonst *mdat = mon->data;
467  | 	int barehand_silver_rings = 0;
468  | 	/* The basic reason we need all these booleans is that we don't want
469  | 	 * a "hit" message when a monster dies, so we have to know how much
470  | 	 * damage it did _before_ outputting a hit message, but any messages
471  | 	 * associated with the damage don't come out until _after_ outputting
472  | 	 * a hit message.
473  | 	 */
474  | 	boolean hittxt = FALSE, destroyed = FALSE;
475  | 	boolean get_dmg_bonus = TRUE;
476  | 	boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE;
477  | 	boolean silvermsg = FALSE;
478  | 	boolean valid_weapon_attack = FALSE;
479  | 	int wtype;
480  | 	struct obj *monwep;
481  | 	char yourbuf[BUFSZ];
482  | 
483  | 	wakeup(mon);
484  | 	if(!obj) {	/* attack with bare hands */
485  | 	    if (mdat == &mons[PM_SHADE])
486  | 		tmp = 0;
487  | 	    else if (martial_bonus())
488  | 		tmp = rnd(4);	/* bonus for martial arts */
489  | 	    else
490  | 		tmp = rnd(2);
491  | 	    valid_weapon_attack = (tmp > 1);
492  | 	    /* blessed gloves give bonuses when fighting 'bare-handed' */
493  | 	    if (uarmg && uarmg->blessed && (is_undead(mdat) || is_demon(mdat)))
494  | 		tmp += rnd(4);
495  | 	    /* So do silver rings.  Note: rings are worn under gloves, so you
496  | 	     * don't get both bonuses.
497  | 	     */
498  | 	    if (!uarmg) {
499  | 		if (uleft && objects[uleft->otyp].oc_material == SILVER)
500  | 		    barehand_silver_rings++;
501  | 		if (uright && objects[uright->otyp].oc_material == SILVER)
502  | 		    barehand_silver_rings++;
503  | 		if (barehand_silver_rings && hates_silver(mdat)) {
504  | 		    tmp += rnd(20);
505  | 		    silvermsg = TRUE;
506  | 		}
507  | 	    }
508  | 	} else {
509  | 	    if(obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
510  | 	       obj->oclass == GEM_CLASS) {
511  | 
512  | 		/* is it not a melee weapon? */
513  | 		if (/* if you strike with a bow... */
514  | 		    is_launcher(obj) ||
515  | 		    /* or strike with a missile in your hand... */
516  | 		    (!thrown && (is_missile(obj) || is_ammo(obj))) ||
517  | 		    /* or use a pole at short range and not mounted... */
518  | 		    (!thrown &&
519  | #ifdef STEED
520  | 		     !u.usteed &&
521  | #endif
522  | 		     is_pole(obj)) ||
523  | 		    /* or throw a missile without the proper bow... */
524  | 		    (is_ammo(obj) && !ammo_and_launcher(obj, uwep))) {
525  | 		    /* then do only 1-2 points of damage */
526  | 		    if (mdat == &mons[PM_SHADE] && obj->otyp != SILVER_ARROW)
527  | 			tmp = 0;
528  | 		    else
529  | 			tmp = rnd(2);
530  | 		} else {
531  | 		    tmp = dmgval(obj, mon);
532  | 		    /* a minimal hit doesn't exercise proficiency */
533  | 		    valid_weapon_attack = (tmp > 1);
534  | 		    if (!valid_weapon_attack || mon == u.ustuck || u.twoweap) {
535  | 			;	/* no special bonuses */
536  | 		    } else if (mon->mflee && Role_if(PM_ROGUE) && !Upolyd) {
537  | 			You("strike %s from behind!", mon_nam(mon));
538  | 			tmp += rnd(u.ulevel);
539  | 			hittxt = TRUE;
540  | 		    } else if (dieroll == 2 && obj == uwep &&
541  | 			  obj->oclass == WEAPON_CLASS &&
542  | 			  (bimanual(obj) ||
543  | 			    (Role_if(PM_SAMURAI) && obj->otyp == KATANA && !uarms)) &&
544  | 			  ((wtype = uwep_skill_type()) != P_NONE &&
545  | 			    P_SKILL(wtype) >= P_SKILLED) &&
546  | 			  ((monwep = MON_WEP(mon)) != 0 &&
547  | 			    weapon_type(monwep) != P_WHIP &&
548  | 			    !obj_resists(monwep,
549  | 				 50 + 15 * greatest_erosion(monwep), 100))) {
550  | 			/*
551  | 			 * 2.5% chance of shattering defender's weapon when
552  | 			 * using a two-handed weapon; less if uwep is rusted.
553  | 			 * [dieroll == 2 is most successful non-beheading or
554  | 			 * -bisecting hit, in case of special artifact damage;
555  | 			 * the percentage chance is (1/20)*(50/100).]
556  | 			 */
557  | 			monwep->owornmask &= ~W_WEP;
558  | 			MON_NOWEP(mon);
559  | 			mon->weapon_check = NEED_WEAPON;
560  | 			pline("%s %s shatter%s from the force of your blow!",
561  | 			      s_suffix(Monnam(mon)), xname(monwep),
562  | 			      (monwep->quan) == 1L ? "s" : "");
563  | 			m_useup(mon, monwep);
564  | 			/* If someone just shattered MY weapon, I'd flee! */
565  | 			if (rn2(4) && !mon->mflee) {
566  | 			    mon->mflee = 1;
567  | 			    mon->mfleetim = d(2,3);
568  | 			}
569  | 			hittxt = TRUE;
570  | 		    }
571  | 
572  | 		    if (obj->oartifact &&
573  | 			artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) {
574  | 			if(mon->mhp <= 0) /* artifact killed monster */
575  | 			    return FALSE;
576  | 			if (tmp == 0) return TRUE;
577  | 			hittxt = TRUE;
578  | 		    }
579  | 		    if (objects[obj->otyp].oc_material == SILVER
580  | 				&& hates_silver(mdat))
581  | 			silvermsg = TRUE;
582  | 		    if(!thrown && obj == uwep && obj->otyp == BOOMERANG &&
583  | 		       !rnl(3)) {
584  | 			pline("As you hit %s, %s breaks into splinters.",
585  | 			      mon_nam(mon), the(xname(obj)));
586  | 			useup(obj);
587  | 			obj = (struct obj *) 0;
588  | 			hittxt = TRUE;
589  | 			if (mdat != &mons[PM_SHADE])
590  | 			    tmp++;
591  | 		    } else if(thrown && (is_ammo(obj) || is_missile(obj))) {
592  | 			if (ammo_and_launcher(obj, uwep)) {
593  | 			    /* Elves and Samurai do extra damage using
594  | 			     * their bows&arrows; they're highly trained.
595  | 			     */
596  | 			    if (Role_if(PM_SAMURAI) &&
597  | 				obj->otyp == YA && uwep->otyp == YUMI)
598  | 				tmp++;
599  | 			    else if (Race_if(PM_ELF) &&
600  | 				     obj->otyp == ELVEN_ARROW &&
601  | 				     uwep->otyp == ELVEN_BOW)
602  | 				tmp++;
603  | 			}
604  | 			if(obj->opoisoned && is_poisonable(obj))
605  | 			    ispoisoned = TRUE;
606  | 		    }
607  | 		}
608  | 	    } else if(obj->oclass == POTION_CLASS) {
609  | 		if (obj->quan > 1L)
610  | 		    setworn(splitobj(obj, 1L), W_WEP);
611  | 		else
612  | 		    setuwep((struct obj *)0);
613  | 		freeinv(obj);
614  | 		potionhit(mon, obj, TRUE);
615  | 		if (mon->mhp <= 0) return FALSE;	/* killed */
616  | 		hittxt = TRUE;
617  | 		/* in case potion effect causes transformation */
618  | 		mdat = mon->data;
619  | 		tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1;
620  | 	    } else {
621  | 		boolean shade_aware = FALSE;
622  | 
623  | 		switch(obj->otyp) {
624  | 		    case BOULDER:		/* 1d20 */
625  | 		    case HEAVY_IRON_BALL:	/* 1d25 */
626  | 		    case IRON_CHAIN:		/* 1d4+1 */
627  | 			tmp = dmgval(obj, mon);
628  | 			shade_aware = TRUE;	/* dmgval handles it */
629  | 			break;
630  | 		    case MIRROR:
631  | 			if (breaktest(obj)) {
632  | 			    You("break %s mirror.  That's bad luck!",
633  | 				shk_your(yourbuf, obj));
634  | 			    change_luck(-2);
635  | 			    useup(obj);
636  | 			    obj = (struct obj *) 0;
637  | 			    hittxt = TRUE;
638  | 			}
639  | 			tmp = 1;
640  | 			break;
641  | #ifdef TOURIST
642  | 		    case EXPENSIVE_CAMERA:
643  | 			You("succeed in destroying %s camera.  Congratulations!",
644  | 			    shk_your(yourbuf, obj));
645  | 			useup(obj);
646  | 			return(TRUE);
647  | #endif
648  | 		    case CORPSE:		/* fixed by polder@cs.vu.nl */
649  | 			if (touch_petrifies(&mons[obj->corpsenm])) {
650  | 			    tmp = 1;
651  | 			    hittxt = TRUE;
652  | 			    You("hit %s with %s corpse.", mon_nam(mon),
653  | 				obj->dknown ? the(mons[obj->corpsenm].mname) :
654  | 				an(mons[obj->corpsenm].mname));
655  | 			    if (!munstone(mon, TRUE))
656  | 				minstapetrify(mon, TRUE);
657  | 			    if (resists_ston(mon)) break;
658  | 			    /* note: hp may be <= 0 even if munstoned==TRUE */
659  | 			    return (boolean) (mon->mhp > 0);
660  | #if 0
661  | 			} else if (touch_petrifies(mdat)) {
662  | 			    /* maybe turn the corpse into a statue? */
663  | #endif
664  | 			}
665  | 			tmp = (obj->corpsenm >= LOW_PM ?
666  | 					mons[obj->corpsenm].msize : 0) + 1;
667  | 			break;
668  | 		    case EGG:
669  | 		      {
670  | #define useup_eggs(o)	{ if (thrown) obfree(o,(struct obj *)0); \
671  | 			  else useupall(o); \
672  | 			  o = (struct obj *)0; }	/* now gone */
673  | 			long cnt = obj->quan;
674  | 
675  | 			tmp = 1;		/* nominal physical damage */
676  | 			get_dmg_bonus = FALSE;
677  | 			hittxt = TRUE;		/* message always given */
678  | 			/* egg is always either used up or transformed, so next
679  | 			   hand-to-hand attack should yield a "bashing" mesg */
680  | 			if (obj == uwep) unweapon = TRUE;
681  | 			if (obj->spe && obj->corpsenm >= LOW_PM) {
682  | 			    if (obj->quan < 5)
683  | 				change_luck((schar) -(obj->quan));
684  | 			    else
685  | 				change_luck(-5);
686  | 			}
687  | 
688  | 			if (touch_petrifies(&mons[obj->corpsenm])) {
689  | 			    /*learn_egg_type(obj->corpsenm);*/
690  | 			    You("hit %s with %s %s egg%s.  Splat!",
691  | 				mon_nam(mon),
692  | 				obj->known ? "the" : cnt > 1L ? "some" : "a",
693  | 				obj->known ? mons[obj->corpsenm].mname : "petrifying",
694  | 				plur(cnt));
695  | 			    obj->known = 1;	/* (not much point...) */
696  | 			    useup_eggs(obj);
697  | 			    if (!munstone(mon, TRUE))
698  | 				minstapetrify(mon, TRUE);
699  | 			    if (resists_ston(mon)) break;
700  | 			    return (boolean) (mon->mhp > 0);
701  | 			} else {	/* ordinary egg(s) */
702  | 			    const char *eggp =
703  | 				     (obj->corpsenm != NON_PM && obj->known) ?
704  | 					      the(mons[obj->corpsenm].mname) :
705  | 					      (cnt > 1L) ? "some" : "an";
706  | 			    You("hit %s with %s egg%s.",
707  | 				mon_nam(mon), eggp, plur(cnt));
708  | 			    if (touch_petrifies(mdat)) {
709  | 				pline_The("egg%s %s alive any more...",
710  | 				      plur(cnt),
711  | 				      (cnt == 1L) ? "isn't" : "aren't");
712  | 				if (obj->timed) obj_stop_timers(obj);
713  | 				obj->otyp = ROCK;
714  | 				obj->oclass = GEM_CLASS;
715  | 				obj->oartifact = 0;
716  | 				obj->spe = 0;
717  | 				obj->known = obj->dknown = obj->bknown = 0;
718  | 				obj->owt = weight(obj);
719  | 				if (thrown) place_object(obj, mon->mx, mon->my);
720  | 			    } else {
721  | 				pline("Splat!");
722  | 				useup_eggs(obj);
723  | 				exercise(A_WIS, FALSE);
724  | 			    }
725  | 			}
726  | 			break;
727  | #undef useup_eggs
728  | 		      }
729  | 		    case CLOVE_OF_GARLIC:	/* no effect against demons */
730  | 			if (is_undead(mdat)) {
731  | 			    mon->mflee = 1;
732  | 			    mon->mfleetim += d(2,4);
733  | 			    pline("%s turns to flee!", Monnam(mon));
734  | 			}
735  | 			tmp = 1;
736  | 			break;
737  | 		    case CREAM_PIE:
738  | 		    case BLINDING_VENOM:
739  | 			mon->msleeping = 0;
740  | 			if (can_blnd(&youmonst, mon, (uchar)
741  | 				    (obj->otyp == BLINDING_VENOM
742  | 				     ? AT_SPIT : AT_WEAP), obj)) {
743  | 			    if (Blind) {
744  | 				pline(obj->otyp == CREAM_PIE ?
745  | 				      "Splat!" : "Splash!");
746  | 			    } else if (obj->otyp == BLINDING_VENOM) {
747  | 				pline_The("venom blinds %s%s!", mon_nam(mon),
748  | 					  mon->mcansee ? "" : " further");
749  | 			    } else {
750  | 				char *whom = mon_nam(mon);
751  | 				/* note: s_suffix returns a modifiable buffer */
752  | 				if (haseyes(mdat)
753  | 				    && mdat != &mons[PM_FLOATING_EYE])
754  | 				    whom = strcat(s_suffix(whom), " face");
755  | 				pline_The("%s splashes over %s!",
756  | 					  xname(obj), whom);
757  | 			    }
758  | 			    setmangry(mon);
759  | 			    mon->mcansee = 0;
760  | 			    tmp = rn1(25, 21);
761  | 			    if(((int) mon->mblinded + tmp) > 127)
762  | 				mon->mblinded = 127;
763  | 			    else mon->mblinded += tmp;
764  | 			} else {
765  | 			    pline(obj->otyp==CREAM_PIE ? "Splat!" : "Splash!");
766  | 			    setmangry(mon);
767  | 			}
768  | 			if (thrown) obfree(obj, (struct obj *)0);
769  | 			else useup(obj);
770  | 			hittxt = TRUE;
771  | 			get_dmg_bonus = FALSE;
772  | 			tmp = 0;
773  | 			break;
774  | 		    case ACID_VENOM: /* thrown (or spit) */
775  | 			if (resists_acid(mon)) {
776  | 				Your("venom hits %s harmlessly.",
777  | 					mon_nam(mon));
778  | 				tmp = 0;
779  | 			} else {
780  | 				Your("venom burns %s!", mon_nam(mon));
781  | 				tmp = dmgval(obj, mon);
782  | 			}
783  | 			if (thrown) obfree(obj, (struct obj *)0);
784  | 			else useup(obj);
785  | 			hittxt = TRUE;
786  | 			get_dmg_bonus = FALSE;
787  | 			break;
788  | 		    default:
789  | 			/* non-weapons can damage because of their weight */
790  | 			/* (but not too much) */
791  | 			tmp = obj->owt/100;
792  | 			if(tmp < 1) tmp = 1;
793  | 			else tmp = rnd(tmp);
794  | 			if(tmp > 6) tmp = 6;
795  | 		}
796  | 
797  | 		if (!shade_aware && mdat == &mons[PM_SHADE] && obj &&
798  | 				objects[obj->otyp].oc_material != SILVER)
799  | 		    tmp = 0;
800  | 	    }
801  | 	}
802  | 
803  | 	/****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG)
804  | 	 *      *OR* if attacking bare-handed!! */
805  | 
806  | 	if (get_dmg_bonus && tmp > 0) {
807  | 		tmp += u.udaminc;
808  | 		/* If you throw using a propellor, you don't get a strength
809  | 		 * bonus but you do get an increase-damage bonus.
810  | 		 */
811  | 		if(!thrown || !obj || !uwep || !ammo_and_launcher(obj, uwep))
812  | 		    tmp += dbon();
813  | 	}
814  | 
815  | 	if (valid_weapon_attack) {
816  | 	    struct obj *wep;
817  | 
818  | 	    /* to be valid a projectile must have had the correct projector */
819  | 	    wep = PROJECTILE(obj) ? uwep : obj;
820  | 	    tmp += weapon_dam_bonus(wep);
821  | 	    /* [this assumes that `!thrown' implies wielded...] */
822  | 	    wtype = thrown ? weapon_type(wep) : uwep_skill_type();
823  | 	    use_skill(wtype, 1);
824  | 	}
825  | 
826  | 	if (ispoisoned) {
827  | 	    int nopoison = (10 - (obj->owt/10));            
828  | 	    if(nopoison < 2) nopoison = 2;
829  | 	    if Role_if(PM_SAMURAI) {
830  | 		You("dishonorably use a poisoned weapon!");
831  | 		adjalign(-sgn(u.ualign.type));
832  | 	    } else if ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10)) {
833  | 		You_feel("like an evil coward for using a poisoned weapon.");
834  | 		adjalign(-1);
835  | 	    }
836  | 	    if (obj && !rn2(nopoison)) {
837  | 		obj->opoisoned = FALSE;
838  | 		Your("%s%s no longer poisoned.", xname(obj),
839  | 		     (obj->quan == 1L) ? " is" : "s are");	/**FIXME**/
840  | 	    }
841  | 	    if (resists_poison(mon))
842  | 		needpoismsg = TRUE;
843  | 	    else if (rn2(10))
844  | 		tmp += rnd(6);
845  | 	    else poiskilled = TRUE;
846  | 	}
847  | 	if (tmp < 1) {
848  | 	    /* make sure that negative damage adjustment can't result
849  | 	       in inadvertently boosting the victim's hit points */
850  | 	    tmp = 0;
851  | 	    if (mdat == &mons[PM_SHADE]) {
852  | 		if (!hittxt) {
853  | 		    Your("attack passes harmlessly through %s.",
854  | 			mon_nam(mon));
855  | 		    hittxt = TRUE;
856  | 		}
857  | 	    } else {
858  | 		if (get_dmg_bonus) tmp = 1;
859  | 	    }
860  | 	}
861  | 
862  | 	/* VERY small chance of stunning opponent if unarmed. */
863  | 	if (tmp > 1 && !thrown && !obj && !uwep && !uarm && !uarms && !Upolyd) {
864  | 	    if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) &&
865  | 			!bigmonst(mdat) && !thick_skinned(mdat)) {
866  | 		if (canspotmon(mon))
867  | 		    pline("%s staggers from your powerful strike!",
868  | 			  Monnam(mon));
869  | 		mon->mstun = 1;
870  | 		hittxt = TRUE;
871  | 		if (mon->mcanmove && mon != u.ustuck) {
872  | 		    xchar mdx, mdy;
873  | 
874  | 		    /* see if the monster has a place to move into */
875  | 		    mdx = mon->mx + u.dx;
876  | 		    mdy = mon->my + u.dy;
877  | 		    if (goodpos(mdx, mdy, mon)) {
878  | 			remove_monster(mon->mx, mon->my);
879  | 			newsym(mon->mx, mon->my);
880  | 			place_monster(mon, mdx, mdy);
881  | 			newsym(mon->mx, mon->my);
882  | 			set_apparxy(mon);
883  | 		    }
884  | 		}
885  | 	    }
886  | 	}
887  | 
888  | 	mon->mhp -= tmp;
889  | 	if(mon->mhp < 1)
890  | 		destroyed = TRUE;
891  | 	if (mon->mtame && (!mon->mflee || mon->mfleetim) && tmp > 0) {
892  | 		unsigned fleetim;
893  | 
894  | 		abuse_dog(mon);
895  | 		mon->mflee = TRUE;		/* Rick Richardson */
896  | 		fleetim = mon->mfleetim + (unsigned)(10 * rnd(tmp));
897  | 		mon->mfleetim = min(fleetim,127);
898  | 	}
899  | 	if((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING])
900  | 		   && obj && obj == uwep
901  | 		   && objects[obj->otyp].oc_material == IRON
902  | 		   && mon->mhp > 1 && !thrown && !mon->mcan
903  | 		   /* && !destroyed  -- guaranteed by mhp > 1 */ ) {
904  | 		if (clone_mon(mon)) {
905  | 			pline("%s divides as you hit it!", Monnam(mon));
906  | 			hittxt = TRUE;
907  | 		}
908  | 	}
909  | 
910  | 	if(!hittxt && !destroyed) {
911  | 		if(thrown)
912  | 		    /* thrown => obj exists */
913  | 		    hit(xname(obj), mon, exclam(tmp) );
914  | 		else if(!flags.verbose) You("hit it.");
915  | 		else You("%s %s%s", Role_if(PM_BARBARIAN) ? "smite" : "hit",
916  | 			 mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
917  | 	}
918  | 
919  | 	if (silvermsg) {
920  | 		const char *fmt;
921  | 		char *whom = mon_nam(mon);
922  | 
923  | 		if (canspotmon(mon)) {
924  | 		    if (barehand_silver_rings == 1)
925  | 			fmt = "Your silver ring sears %s!";
926  | 		    else if (barehand_silver_rings == 2)
927  | 			fmt = "Your silver rings sear %s!";
928  | 		    else
929  | 			fmt = "The silver sears %s!";
930  | 		} else {
931  | 		    *whom = highc(*whom);	/* "it" -> "It" */
932  | 		    fmt = "%s is seared!";
933  | 		}
934  | 		/* note: s_suffix returns a modifiable buffer */
935  | 		if (!noncorporeal(mdat))
936  | 		    whom = strcat(s_suffix(whom), " flesh");
937  | 		pline(fmt, whom);
938  | 	}
939  | 
940  | 	if (needpoismsg)
941  | 		pline_The("poison doesn't seem to affect %s.", mon_nam(mon));
942  | 	if (poiskilled) {
943  | 		pline_The("poison was deadly...");
944  | 		xkilled(mon, 0);
945  | 		return FALSE;
946  | 	} else if (destroyed) {
947  | 		killed(mon);	/* takes care of most messages */
948  | 	} else if(u.umconf && !thrown) {
949  | 		nohandglow(mon);
950  | 		if(!mon->mconf && !resist(mon, '+', 0, NOTELL)) {
951  | 			mon->mconf = 1;
952  | 			if (!mon->mstun && mon->mcanmove && !mon->msleeping &&
953  | 				canseemon(mon))
954  | 			    pline("%s appears confused.", Monnam(mon));
955  | 		}
956  | 	}
957  | 
958  | 	return((boolean)(destroyed ? FALSE : TRUE));
959  | }
960  | 
961  | /* check whether slippery clothing protects from hug or wrap attack */
962  | /* [currently assumes that you are the attacker] */
963  | STATIC_OVL boolean
964  | m_slips_free(mdef, mattk)
965  | struct monst *mdef;
966  | struct attack *mattk;
967  | {
968  | 	struct obj *obj;
969  | 
970  | 	if (mattk->adtyp == AD_DRIN) {
971  | 	    /* intelligence drain attacks the head */
972  | 	    obj = which_armor(mdef, W_ARMH);
973  | 	} else {
974  | 	    /* grabbing attacks the body */
975  | 	    obj = which_armor(mdef, W_ARMC);		/* cloak */
976  | 	    if (!obj) obj = which_armor(mdef, W_ARM);	/* suit */
977  | #ifdef TOURIST
978  | 	    if (!obj) obj = which_armor(mdef, W_ARMU);	/* shirt */
979  | #endif
980  | 	}
981  | 
982  | 	/* if your cloak/armor is greased, monster slips off; this
983  | 	   protection might fail (33% chance) when the armor is cursed */
984  | 	if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) &&
985  | 		(!obj->cursed || rn2(3))) {
986  | 	    You("%s %s %s %s!",
987  | 		mattk->adtyp == AD_WRAP ?
988  | 			"slip off of" : "grab, but cannot hold onto",
989  | 		s_suffix(mon_nam(mdef)),
990  | 		obj->greased ? "greased" : "slippery",
991  | 		/* avoid "slippery slippery cloak"
992  | 		   for undiscovered oilskin cloak */
993  | 		(obj->greased || objects[obj->otyp].oc_name_known) ?
994  | 			xname(obj) : "cloak");
995  | 
996  | 	    if (obj->greased && !rn2(2)) {
997  | 		pline_The("grease wears off.");
998  | 		obj->greased = 0;
999  | 	    }
1000 | 	    return TRUE;
1001 | 	}
1002 | 	return FALSE;
1003 | }
1004 | 
1005 | STATIC_DCL void NDECL(demonpet);
1006 | /*
1007 |  * Send in a demon pet for the hero.  Exercise wisdom.
1008 |  *
1009 |  * This function used to be inline to damageum(), but the Metrowerks compiler
1010 |  * (DR4 and DR4.5) screws up with an internal error 5 "Expression Too Complex."
1011 |  * Pulling it out makes it work.
1012 |  */
1013 | STATIC_OVL void
1014 | demonpet()
1015 | {
1016 | 	struct permonst *pm;
1017 | 	struct monst *dtmp;
1018 | 
1019 | 	pline("Some hell-p has arrived!");
1020 | 	pm = !rn2(6) ? &mons[ndemon(u.ualign.type)] : youmonst.data;
1021 | 	if ((dtmp = makemon(pm, u.ux, u.uy, NO_MM_FLAGS)) != 0)
1022 | 	    (void)tamedog(dtmp, (struct obj *)0);
1023 | 	exercise(A_WIS, TRUE);
1024 | }
1025 | 
1026 | /*
1027 |  * Player uses theft attack against monster.
1028 |  *
1029 |  * If the target is wearing body armor, take all of its possesions;
1030 |  * otherwise, take one object.  [Is this really the behavior we want?]
1031 |  *
1032 |  * This routine implicitly assumes that there is no way to be able to
1033 |  * resist petfication (ie, be polymorphed into a xorn or golem) at the
1034 |  * same time as being able to steal (poly'd into nymph or succubus).
1035 |  * If that ever changes, the check for touching a cockatrice corpse
1036 |  * will need to be smarter about whether to break out of the theft loop.
1037 |  */
1038 | STATIC_OVL void
1039 | steal_it(mdef, mattk)
1040 | struct monst *mdef;
1041 | struct attack *mattk;
1042 | {
1043 | 	struct obj *otmp, *stealoid, **minvent_ptr;
1044 | 	long unwornmask;
1045 | 
1046 | 	if (!mdef->minvent) return;		/* nothing to take */
1047 | 
1048 | 	/* look for worn body armor */
1049 | 	stealoid = (struct obj *)0;
1050 | 	if (could_seduce(&youmonst, mdef, mattk)) {
1051 | 	    /* find armor, and move it to end of inventory in the process */
1052 | 	    minvent_ptr = &mdef->minvent;
1053 | 	    while ((otmp = *minvent_ptr) != 0)
1054 | 		if (otmp->owornmask & W_ARM) {
1055 | 		    if (stealoid) panic("steal_it: multiple worn suits");
1056 | 		    *minvent_ptr = otmp->nobj;	/* take armor out of minvent */
1057 | 		    stealoid = otmp;
1058 | 		    stealoid->nobj = (struct obj *)0;
1059 | 		} else {
1060 | 		    minvent_ptr = &otmp->nobj;
1061 | 		}
1062 | 	    *minvent_ptr = stealoid;	/* put armor back into minvent */
1063 | 	}
1064 | 
1065 | 	if (stealoid) {		/* we will be taking everything */
1066 | 	    if (gender(mdef) == (int) u.mfemale &&
1067 | 			youmonst.data->mlet == S_NYMPH)
1068 | 		You("charm %s.  She gladly hands over her possessions.",
1069 | 		    mon_nam(mdef));
1070 | 	    else
1071 | 		You("seduce %s and %s starts to take off %s clothes.",
1072 | 		    mon_nam(mdef), he[pronoun_gender(mdef)],
1073 | 		    his[pronoun_gender(mdef)]);
1074 | 	}
1075 | 
1076 | 	while ((otmp = mdef->minvent) != 0) {
1077 | 	    /* take the object away from the monster */
1078 | 	    obj_extract_self(otmp);
1079 | 	    if ((unwornmask = otmp->owornmask) != 0L) {
1080 | 		mdef->misc_worn_check &= ~unwornmask;
1081 | 		otmp->owornmask = 0L;
1082 | 		update_mon_intrinsics(mdef, otmp, FALSE);
1083 | 
1084 | 		if (otmp == stealoid)	/* special message for final item */
1085 | 		    pline("%s finishes taking off %s suit.",
1086 | 			  Monnam(mdef), his[pronoun_gender(mdef)]);
1087 | 	    }
1088 | 	    /* give the object to the character */
1089 | 	    otmp = hold_another_object(otmp, "You steal %s.",
1090 | 				       doname(otmp), "You steal: ");
1091 | 	    if (otmp->otyp == CORPSE &&
1092 | 		    touch_petrifies(&mons[otmp->corpsenm]) && !uarmg) {
1093 | 		char kbuf[BUFSZ];
1094 | 
1095 | 		Sprintf(kbuf, "stolen %s corpse", mons[otmp->corpsenm].mname);
1096 | 		instapetrify(kbuf);
1097 | 		break;		/* stop the theft even if hero survives */
1098 | 	    }
1099 | 	    /* more take-away handling, after theft message */
1100 | 	    if (unwornmask & W_WEP) {		/* stole wielded weapon */
1101 | 		possibly_unwield(mdef);
1102 | 	    } else if (unwornmask & W_ARMG) {	/* stole worn gloves */
1103 | 		mselftouch(mdef, (const char *)0, TRUE);
1104 | 		if (mdef->mhp <= 0)	/* it's now a statue */
1105 | 		    return;		/* can't continue stealing */
1106 | 	    }
1107 | 
1108 | 	    if (!stealoid) break;	/* only taking one item */
1109 | 	}
1110 | }
1111 | 
1112 | int
1113 | damageum(mdef, mattk)
1114 | register struct monst *mdef;
1115 | register struct attack *mattk;
1116 | {
1117 | 	register struct permonst *pd = mdef->data;
1118 | 	register int	tmp = d((int)mattk->damn, (int)mattk->damd);
1119 | 
1120 | 	if (is_demon(youmonst.data) && !rn2(13) && !uwep
1121 | 		&& u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS
1122 | 		&& u.umonnum != PM_BALROG) {
1123 | 	    demonpet();
1124 | 	    return(0);
1125 | 	}
1126 | 	switch(mattk->adtyp) {
1127 | 	    case AD_STUN:
1128 | 		if(!Blind)
1129 | 		    pline("%s staggers for a moment.", Monnam(mdef));
1130 | 		mdef->mstun = 1;
1131 | 		/* fall through to next case */
1132 | 	    case AD_WERE:	    /* no effect on monsters */
1133 | 	    case AD_HEAL:
1134 | 	    case AD_LEGS:
1135 | 	    case AD_PHYS:
1136 | 		if(mattk->aatyp == AT_WEAP) {
1137 | 		    if(uwep) tmp = 0;
1138 | 		} else if(mattk->aatyp == AT_KICK) {
1139 | 		    if(thick_skinned(mdef->data)) tmp = 0;
1140 | 		    if(mdef->data == &mons[PM_SHADE]) {
1141 | 			if (!(uarmf && uarmf->blessed)) {
1142 | 			    impossible("bad shade attack function flow?");
1143 | 			    tmp = 0;
1144 | 			} else
1145 | 			    tmp = rnd(4); /* bless damage */
1146 | 		    }
1147 | 		}
1148 | 		break;
1149 | 	    case AD_FIRE:
1150 | 		if (!Blind)
1151 | 		    pline("%s is %s!", Monnam(mdef),
1152 | 			  mattk->aatyp == AT_HUGS ?
1153 | 				"being roasted" : "on fire");
1154 | 		if (pd == &mons[PM_STRAW_GOLEM] ||
1155 | 		    pd == &mons[PM_PAPER_GOLEM]) {
1156 | 		    if (!Blind)
1157 | 		    	pline("%s burns completely!", Monnam(mdef));
1158 | 		    xkilled(mdef,0);
1159 | 		}
1160 | 		tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
1161 | 		tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
1162 | 		if (resists_fire(mdef)) {
1163 | 		    if (!Blind)
1164 | 			pline_The("fire doesn't heat %s!", mon_nam(mdef));
1165 | 		    golemeffects(mdef, AD_FIRE, tmp);
1166 | 		    shieldeff(mdef->mx, mdef->my);
1167 | 		    tmp = 0;
1168 | 		}
1169 | 		/* only potions damage resistant players in destroy_item */
1170 | 		tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
1171 | 		break;
1172 | 	    case AD_COLD:
1173 | 		if (!Blind) pline("%s is covered in frost!", Monnam(mdef));
1174 | 		if (resists_cold(mdef)) {
1175 | 		    shieldeff(mdef->mx, mdef->my);
1176 | 		    if (!Blind)
1177 | 			pline_The("frost doesn't chill %s!", mon_nam(mdef));
1178 | 		    golemeffects(mdef, AD_COLD, tmp);
1179 | 		    tmp = 0;
1180 | 		}
1181 | 		tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
1182 | 		break;
1183 | 	    case AD_ELEC:
1184 | 		if (!Blind) pline("%s is zapped!", Monnam(mdef));
1185 | 		tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
1186 | 		if (resists_elec(mdef)) {
1187 | 		    if (!Blind)
1188 | 			pline_The("zap doesn't shock %s!", mon_nam(mdef));
1189 | 		    golemeffects(mdef, AD_ELEC, tmp);
1190 | 		    shieldeff(mdef->mx, mdef->my);
1191 | 		    tmp = 0;
1192 | 		}
1193 | 		/* only rings damage resistant players in destroy_item */
1194 | 		tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
1195 | 		break;
1196 | 	    case AD_ACID:
1197 | 		if (resists_acid(mdef)) tmp = 0;
1198 | 		break;
1199 | 	    case AD_STON:
1200 | 		if (!munstone(mdef, TRUE))
1201 | 		    minstapetrify(mdef, TRUE);
1202 | 		tmp = 0;
1203 | 		break;
1204 | #ifdef SEDUCE
1205 | 	    case AD_SSEX:
1206 | #endif
1207 | 	    case AD_SEDU:
1208 | 	    case AD_SITM:
1209 | 		steal_it(mdef, mattk);
1210 | 		tmp = 0;
1211 | 		break;
1212 | 	    case AD_SGLD:
1213 | 		if (mdef->mgold) {
1214 | 		    u.ugold += mdef->mgold;
1215 | 		    mdef->mgold = 0;
1216 | 		    Your("purse feels heavier.");
1217 | 		}
1218 | 		exercise(A_DEX, TRUE);
1219 | 		tmp = 0;
1220 | 		break;
1221 | 	    case AD_TLPT:
1222 | 		if(tmp <= 0) tmp = 1;
1223 | 		if(tmp < mdef->mhp) {
1224 | 		    char nambuf[BUFSZ];
1225 | 		    boolean u_saw_mon = canseemon(mdef);
1226 | 		    /* record the name before losing sight of monster */
1227 | 		    Strcpy(nambuf, Monnam(mdef));
1228 | 		    if (u_teleport_mon(mdef, FALSE) &&
1229 | 			    u_saw_mon && !canseemon(mdef))
1230 | 			pline("%s suddenly disappears!", nambuf);
1231 | 		}
1232 | 		break;
1233 | 	    case AD_BLND:
1234 | 		if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj*)0)) {
1235 | 		    if(!Blind && mdef->mcansee)
1236 | 			pline("%s is blinded.", Monnam(mdef));
1237 | 		    mdef->mcansee = 0;
1238 | 		    tmp += mdef->mblinded;
1239 | 		    if (tmp > 127) tmp = 127;
1240 | 		    mdef->mblinded = tmp;
1241 | 		}
1242 | 		tmp = 0;
1243 | 		break;
1244 | 	    case AD_CURS:
1245 | 		if (night() && !rn2(10) && !mdef->mcan) {
1246 | 		    if (mdef->data == &mons[PM_CLAY_GOLEM]) {
1247 | 			if (!Blind)
1248 | 			    pline("Some writing vanishes from %s head!",
1249 | 				s_suffix(mon_nam(mdef)));
1250 | 			xkilled(mdef, 0);
1251 | 			/* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1252 | 		    } else {
1253 | 			mdef->mcan = 1;
1254 | 			You("chuckle.");
1255 | 		    }
1256 | 		}
1257 | 		tmp = 0;
1258 | 		break;
1259 | 	    case AD_DRLI:
1260 | 		if (rn2(2) && !resists_drli(mdef)) {
1261 | 			int xtmp = d(2,6);
1262 | 			pline("%s suddenly seems weaker!", Monnam(mdef));
1263 | 			mdef->mhpmax -= xtmp;
1264 | 			if ((mdef->mhp -= xtmp) <= 0 || !mdef->m_lev) {
1265 | 				pline("%s dies!", Monnam(mdef));
1266 | 				xkilled(mdef,0);
1267 | 			} else
1268 | 				mdef->m_lev--;
1269 | 		}
1270 | 		tmp = 0;
1271 | 		break;
1272 | 	    case AD_RUST:
1273 | 		if (pd == &mons[PM_IRON_GOLEM]) {
1274 | 			pline("%s falls to pieces!", Monnam(mdef));
1275 | 			xkilled(mdef,0);
1276 | 		}
1277 | 		hurtmarmor(mdef, AD_RUST);
1278 | 		tmp = 0;
1279 | 		break;
1280 | 	    case AD_CORRODE:
1281 | 		hurtmarmor(mdef, AD_CORRODE);
1282 | 		tmp = 0;
1283 | 		break;
1284 | 	    case AD_DCAY:
1285 | 		if (pd == &mons[PM_WOOD_GOLEM] ||
1286 | 		    pd == &mons[PM_LEATHER_GOLEM]) {
1287 | 			pline("%s falls to pieces!", Monnam(mdef));
1288 | 			xkilled(mdef,0);
1289 | 		}
1290 | 		hurtmarmor(mdef, AD_DCAY);
1291 | 		tmp = 0;
1292 | 		break;
1293 | 	    case AD_DRST:
1294 | 	    case AD_DRDX:
1295 | 	    case AD_DRCO:
1296 | 		if (!rn2(8)) {
1297 | 		    Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk));
1298 | 		    if (resists_poison(mdef))
1299 | 			pline_The("poison doesn't seem to affect %s.",
1300 | 				mon_nam(mdef));
1301 | 		    else {
1302 | 			if (!rn2(10)) {
1303 | 			    Your("poison was deadly...");
1304 | 			    tmp = mdef->mhp;
1305 | 			} else tmp += rn1(10,6);
1306 | 		    }
1307 | 		}
1308 | 		break;
1309 | 	    case AD_DRIN:
1310 | 		if (notonhead || !has_head(mdef->data)) {
1311 | 		    pline("%s doesn't seem harmed.", Monnam(mdef));
1312 | 		    tmp = 0;
1313 | 		    break;
1314 | 		}
1315 | 		if (m_slips_free(mdef, mattk)) break;
1316 | 
1317 | 		if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) {
1318 | 		    pline("%s helmet blocks your attack to %s head.",
1319 | 			  s_suffix(Monnam(mdef)), his[pronoun_gender(mdef)]);
1320 | 		    break;
1321 | 		}
1322 | 
1323 | 		You("eat %s brain!", s_suffix(mon_nam(mdef)));
1324 | 		u.uconduct.food++;
1325 | 		if (!vegan(mdef->data))
1326 | 		    u.uconduct.unvegan++;
1327 | 		if (!vegetarian(mdef->data))
1328 | 		    violated_vegetarian();
1329 | 		if (mindless(mdef->data)) {
1330 | 		    pline("%s doesn't notice.", Monnam(mdef));
1331 | 		    break;
1332 | 		}
1333 | 		tmp += rnd(10);
1334 | 		morehungry(-rnd(30)); /* cannot choke */
1335 | 		if (ABASE(A_INT) < AMAX(A_INT)) {
1336 | 			ABASE(A_INT) += rnd(4);
1337 | 			if (ABASE(A_INT) > AMAX(A_INT))
1338 | 				ABASE(A_INT) = AMAX(A_INT);
1339 | 			flags.botl = 1;
1340 | 		}
1341 | 		exercise(A_WIS, TRUE);
1342 | 		break;
1343 | 	    case AD_STCK:
1344 | 		if (!sticks(mdef->data))
1345 | 		    u.ustuck = mdef; /* it's now stuck to you */
1346 | 		break;
1347 | 	    case AD_WRAP:
1348 | 		if (!sticks(mdef->data)) {
1349 | 		    if (!u.ustuck && !rn2(10)) {
1350 | 			if (m_slips_free(mdef, mattk)) {
1351 | 			    tmp = 0;
1352 | 			} else {
1353 | 			    You("swing yourself around %s!",
1354 | 				  mon_nam(mdef));
1355 | 			    u.ustuck = mdef;
1356 | 			}
1357 | 		    } else if(u.ustuck == mdef) {
1358 | 			/* Monsters don't wear amulets of magical breathing */
1359 | 			if (is_pool(u.ux,u.uy) && !is_swimmer(mdef->data)) {
1360 | 			    You("drown %s...", mon_nam(mdef));
1361 | 			    tmp = mdef->mhp;
1362 | 			} else if(mattk->aatyp == AT_HUGS)
1363 | 			    pline("%s is being crushed.", Monnam(mdef));
1364 | 		    } else {
1365 | 			tmp = 0;
1366 | 			if (flags.verbose)
1367 | 			    You("brush against %s %s.",
1368 | 				s_suffix(mon_nam(mdef)),
1369 | 				mbodypart(mdef, LEG));
1370 | 		    }
1371 | 		} else tmp = 0;
1372 | 		break;
1373 | 	    case AD_PLYS:
1374 | 		if (mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
1375 | 		    if (!Blind) pline("%s is frozen by you!", Monnam(mdef));
1376 | 		    mdef->mcanmove = 0;
1377 | 		    mdef->mfrozen = rnd(10);
1378 | 		}
1379 | 		break;
1380 | 	    case AD_SLEE:
1381 | 		if (!mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) {
1382 | 		    if (!Blind)
1383 | 			pline("%s is put to sleep by you!", Monnam(mdef));
1384 | 		    slept_monst(mdef);
1385 | 		}
1386 | 		break;
1387 | 	    case AD_SLIM:
1388 | 	    	if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
1389 | 	    			mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
1390 | 	    			mdef->data != &mons[PM_GREEN_SLIME]) {
1391 | 	    	    You("turn %s into slime.", mon_nam(mdef));
1392 | 	    	    (void) newcham(mdef, &mons[PM_GREEN_SLIME]);
1393 | 	    	    tmp = 0;
1394 | 	    	}
1395 | 	    	break;
1396 | 	    case AD_ENCH:	/* KMH -- remove enchantment (disenchanter) */
1397 | 			/* There's no msomearmor() function, so just do damage */
1398 | 			break;
1399 | 	    default:	tmp = 0;
1400 | 			break;
1401 | 	}
1402 | 
1403 | 	if((mdef->mhp -= tmp) < 1) {
1404 | 	    if (mdef->mtame && !cansee(mdef->mx,mdef->my)) {
1405 | 		You_feel("embarrassed for a moment.");
1406 | 		if (tmp) xkilled(mdef, 0); /* !tmp but hp<1: already killed */
1407 | 	    } else if (!flags.verbose) {
1408 | 		You("destroy it!");
1409 | 		if (tmp) xkilled(mdef, 0);
1410 | 	    } else
1411 | 		if (tmp) killed(mdef);
1412 | 	    return(2);
1413 | 	}
1414 | 	return(1);
1415 | }
1416 | 
1417 | STATIC_OVL int
1418 | explum(mdef, mattk)
1419 | register struct monst *mdef;
1420 | register struct attack *mattk;
1421 | {
1422 | 	register int tmp = d((int)mattk->damn, (int)mattk->damd);
1423 | 
1424 | 	You("explode!");
1425 | 	switch(mattk->adtyp) {
1426 | 	    boolean resistance; /* only for cold/fire/elec */
1427 | 
1428 | 	    case AD_BLND:
1429 | 		if (!resists_blnd(mdef)) {
1430 | 		    pline("%s is blinded by your flash of light!", Monnam(mdef));
1431 | 		    mdef->mblinded = min((int)mdef->mblinded + tmp, 127);
1432 | 		    mdef->mcansee = 0;
1433 | 		}
1434 | 		break;
1435 | 	    case AD_HALU:
1436 | 		if (haseyes(mdef->data) && mdef->mcansee) {
1437 | 		    pline("%s is affected by your flash of light!",
1438 | 			  Monnam(mdef));
1439 | 		    mdef->mconf = 1;
1440 | 		}
1441 | 		break;
1442 | 	    case AD_COLD:
1443 | 		resistance = resists_cold(mdef);
1444 | 		goto common;
1445 | 	    case AD_FIRE:
1446 | 		resistance = resists_fire(mdef);
1447 | 		goto common;
1448 | 	    case AD_ELEC:
1449 | 		resistance = resists_elec(mdef);
1450 | common:
1451 | 		if (!resistance) {
1452 | 		    pline("%s gets blasted!", Monnam(mdef));
1453 | 		    mdef->mhp -= tmp;
1454 | 		    if (mdef->mhp <= 0) {
1455 | 			 killed(mdef);
1456 | 			 return(2);
1457 | 		    }
1458 | 		} else {
1459 | 		    shieldeff(mdef->mx, mdef->my);
1460 | 		    if (is_golem(mdef->data))
1461 | 			golemeffects(mdef, (int)mattk->adtyp, tmp);
1462 | 		    else
1463 | 			pline_The("blast doesn't seem to affect %s.",
1464 | 				mon_nam(mdef));
1465 | 		}
1466 | 		break;
1467 | 	    default:
1468 | 		break;
1469 | 	}
1470 | 	return(1);
1471 | }
1472 | 
1473 | STATIC_OVL void
1474 | start_engulf(mdef)
1475 | struct monst *mdef;
1476 | {
1477 | 	if (!Invisible) {
1478 | 		map_location(u.ux, u.uy, TRUE);
1479 | 		tmp_at(DISP_ALWAYS, mon_to_glyph(&youmonst));
1480 | 		tmp_at(mdef->mx, mdef->my);
1481 | 	}
1482 | 	You("engulf %s!", mon_nam(mdef));
1483 | 	delay_output();
1484 | 	delay_output();
1485 | }
1486 | 
1487 | STATIC_OVL void
1488 | end_engulf()
1489 | {
1490 | 	if (!Invisible) {
1491 | 		tmp_at(DISP_END, 0);
1492 | 		newsym(u.ux, u.uy);
1493 | 	}
1494 | }
1495 | 
1496 | STATIC_OVL int
1497 | gulpum(mdef,mattk)
1498 | register struct monst *mdef;
1499 | register struct attack *mattk;
1500 | {
1501 | 	register int tmp;
1502 | 	register int dam = d((int)mattk->damn, (int)mattk->damd);
1503 | 	struct obj *otmp;
1504 | 	/* Not totally the same as for real monsters.  Specifically, these
1505 | 	 * don't take multiple moves.  (It's just too hard, for too little
1506 | 	 * result, to program monsters which attack from inside you, which
1507 | 	 * would be necessary if done accurately.)  Instead, we arbitrarily
1508 | 	 * kill the monster immediately for AD_DGST and we regurgitate them
1509 | 	 * after exactly 1 round of attack otherwise.  -KAA
1510 | 	 */
1511 | 
1512 | 	if(mdef->data->msize >= MZ_HUGE) return 0;
1513 | 
1514 | 	if(u.uhunger < 1500 && !u.uswallow) {
1515 | 	    for (otmp = mdef->minvent; otmp; otmp = otmp->nobj)
1516 | 		(void) snuff_lit(otmp);
1517 | 
1518 | 	    if(!touch_petrifies(mdef->data) || Stone_resistance) {
1519 | #ifdef LINT	/* static char msgbuf[BUFSZ]; */
1520 | 		char msgbuf[BUFSZ];
1521 | #else
1522 | 		static char msgbuf[BUFSZ];
1523 | #endif
1524 | 		start_engulf(mdef);
1525 | 		switch(mattk->adtyp) {
1526 | 		    case AD_DGST:
1527 | 			/* eating a Rider or its corpse is fatal */
1528 | 			if (is_rider(mdef->data)) {
1529 | 			 pline("Unfortunately, digesting any of it is fatal.");
1530 | 			    end_engulf();
1531 | 			    Sprintf(msgbuf, "unwisely tried to eat %s",
1532 | 				    mdef->data->mname);
1533 | 			    killer = msgbuf;
1534 | 			    killer_format = NO_KILLER_PREFIX;
1535 | 			    done(DIED);
1536 | 			    return 0;		/* lifesaved */
1537 | 			}
1538 | 
1539 | 			if (Slow_digestion) {
1540 | 			    dam = 0;
1541 | 			    break;
1542 | 			}
1543 | 
1544 | 			/* KMH, conduct */
1545 | 			u.uconduct.food++;
1546 | 			if (!vegan(mdef->data))
1547 | 			     u.uconduct.unvegan++;
1548 | 			if (!vegetarian(mdef->data))
1549 | 			     violated_vegetarian();
1550 | 
1551 | 			/* Use up amulet of life saving */
1552 | 			if (!!(otmp = mlifesaver(mdef))) m_useup(mdef, otmp);
1553 | 
1554 | 			newuhs(FALSE);
1555 | 			xkilled(mdef,2);
1556 | 			if (mdef->mhp > 0) { /* monster lifesaved */
1557 | 			    You("hurriedly regurgitate the sizzling in your stomach.");
1558 | 			} else {
1559 | 			    u.uhunger += mdef->data->cnutrit;
1560 | 			    Sprintf(msgbuf, "You totally digest %s.",
1561 | 					    mon_nam(mdef));
1562 | 			    if ((tmp = 3 + (mdef->data->cwt >> 6)) != 0) {
1563 | 				/* setting afternmv = end_engulf is tempting,
1564 | 				 * but will cause problems if the player is
1565 | 				 * attacked (which uses his real location) or
1566 | 				 * if his See_invisible wears off
1567 | 				 */
1568 | 				You("digest %s.", mon_nam(mdef));
1569 | 				if (Slow_digestion) tmp *= 2;
1570 | 				nomul(-tmp);
1571 | 				nomovemsg = msgbuf;
1572 | 			    } else pline("%s", msgbuf);
1573 | 			    exercise(A_CON, TRUE);
1574 | 			}
1575 | 			end_engulf();
1576 | 			return(2);
1577 | 		    case AD_PHYS:
1578 | 			pline("%s is pummeled with your debris!",Monnam(mdef));
1579 | 			break;
1580 | 		    case AD_ACID:
1581 | 			pline("%s is covered with your goo!", Monnam(mdef));
1582 | 			if (resists_acid(mdef)) {
1583 | 			    pline("It seems harmless to %s.", mon_nam(mdef));
1584 | 			    dam = 0;
1585 | 			}
1586 | 			break;
1587 | 		    case AD_BLND:
1588 | 			if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj *)0)) {
1589 | 			    if (mdef->mcansee)
1590 | 				pline("%s can't see in there!", Monnam(mdef));
1591 | 			    mdef->mcansee = 0;
1592 | 			    dam += mdef->mblinded;
1593 | 			    if (dam > 127) dam = 127;
1594 | 			    mdef->mblinded = dam;
1595 | 			}
1596 | 			dam = 0;
1597 | 			break;
1598 | 		    case AD_ELEC:
1599 | 			if (rn2(2)) {
1600 | 			    pline_The("air around %s crackles with electricity.", mon_nam(mdef));
1601 | 			    if (resists_elec(mdef)) {
1602 | 				pline("%s seems unhurt.", Monnam(mdef));
1603 | 				dam = 0;
1604 | 			    }
1605 | 			    golemeffects(mdef,(int)mattk->adtyp,dam);
1606 | 			} else dam = 0;
1607 | 			break;
1608 | 		    case AD_COLD:
1609 | 			if (rn2(2)) {
1610 | 			    if (resists_cold(mdef)) {
1611 | 				pline("%s seems mildly chilly.", Monnam(mdef));
1612 | 				dam = 0;
1613 | 			    } else
1614 | 				pline("%s is freezing to death!",Monnam(mdef));
1615 | 			    golemeffects(mdef,(int)mattk->adtyp,dam);
1616 | 			} else dam = 0;
1617 | 			break;
1618 | 		    case AD_FIRE:
1619 | 			if (rn2(2)) {
1620 | 			    if (resists_fire(mdef)) {
1621 | 				pline("%s seems mildly hot.", Monnam(mdef));
1622 | 				dam = 0;
1623 | 			    } else
1624 | 				pline("%s is burning to a crisp!",Monnam(mdef));
1625 | 			    golemeffects(mdef,(int)mattk->adtyp,dam);
1626 | 			} else dam = 0;
1627 | 			break;
1628 | 		}
1629 | 		end_engulf();
1630 | 		if ((mdef->mhp -= dam) <= 0) {
1631 | 		    killed(mdef);
1632 | 		    if (mdef->mhp <= 0)	/* not lifesaved */
1633 | 			return(2);
1634 | 		}
1635 | 		You("%s %s!", is_animal(youmonst.data) ? "regurgitate"
1636 | 			: "expel", mon_nam(mdef));
1637 | 		if (Slow_digestion || is_animal(youmonst.data)) {
1638 | 		    pline("Obviously, you didn't like %s taste.",
1639 | 			  s_suffix(mon_nam(mdef)));
1640 | 		}
1641 | 	    } else {
1642 | 		char kbuf[BUFSZ];
1643 | 
1644 | 		You("bite into %s.", mon_nam(mdef));
1645 | 		Sprintf(kbuf, "swallowing %s whole", an(mdef->data->mname));
1646 | 		instapetrify(kbuf);
1647 | 	    }
1648 | 	}
1649 | 	return(0);
1650 | }
1651 | 
1652 | void
1653 | missum(mdef,mattk)
1654 | register struct monst *mdef;
1655 | register struct attack *mattk;
1656 | {
1657 | 	if (could_seduce(&youmonst, mdef, mattk))
1658 | 		You("pretend to be friendly to %s.", mon_nam(mdef));
1659 | 	else if(canspotmon(mdef) && flags.verbose)
1660 | 		You("miss %s.", mon_nam(mdef));
1661 | 	else
1662 | 		You("miss it.");
1663 | 	if (!mdef->msleeping && mdef->mcanmove)
1664 | 		wakeup(mdef);
1665 | }
1666 | 
1667 | STATIC_OVL boolean
1668 | hmonas(mon, tmp)		/* attack monster as a monster. */
1669 | register struct monst *mon;
1670 | register int tmp;
1671 | {
1672 | 	register struct attack *mattk;
1673 | 	int	i, sum[NATTK], hittmp = 0;
1674 | 	int	nsum = 0;
1675 | 	int	dhit = 0;
1676 | 
1677 | 	for(i = 0; i < NATTK; i++) {
1678 | 
1679 | 	    sum[i] = 0;
1680 | 	    mattk = &(youmonst.data->mattk[i]);
1681 | 	    switch(mattk->aatyp) {
1682 | 		case AT_WEAP:
1683 | use_weapon:
1684 | 	/* Certain monsters don't use weapons when encountered as enemies,
1685 | 	 * but players who polymorph into them have hands or claws and thus
1686 | 	 * should be able to use weapons.  This shouldn't prohibit the use
1687 | 	 * of most special abilities, either.
1688 | 	 */
1689 | 	/* Potential problem: if the monster gets multiple weapon attacks,
1690 | 	 * we currently allow the player to get each of these as a weapon
1691 | 	 * attack.  Is this really desirable?
1692 | 	 */
1693 | 			if (uwep) {
1694 | 			    hittmp = hitval(uwep, mon);
1695 | 			    hittmp += weapon_hit_bonus(uwep);
1696 | 			    tmp += hittmp;
1697 | 			}
1698 | 			dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
1699 | 			/* KMH -- Don't accumulate to-hit bonuses */
1700 | 			if (uwep) tmp -= hittmp;
1701 | 			/* Enemy dead, before any special abilities used */
1702 | 			if (!known_hitum(mon,&dhit,mattk)) {
1703 | 			    sum[i] = 2;
1704 | 			    break;
1705 | 			} else sum[i] = 1;
1706 | 			/* might be a worm that gets cut in half */
1707 | 			if (m_at(u.ux+u.dx, u.uy+u.dy) != mon) return((boolean)(nsum != 0));
1708 | 			/* Do not print "You hit" message, since known_hitum
1709 | 			 * already did it.
1710 | 			 */
1711 | 			if (dhit && mattk->adtyp != AD_SPEL
1712 | 				&& mattk->adtyp != AD_PHYS)
1713 | 				sum[i] = damageum(mon,mattk);
1714 | 			break;
1715 | 		case AT_CLAW:
1716 | 			if (i==0 && uwep && !cantwield(youmonst.data)) goto use_weapon;
1717 | #ifdef SEDUCE
1718 | 			/* succubi/incubi are humanoid, but their _second_
1719 | 			 * attack is AT_CLAW, not their first...
1720 | 			 */
1721 | 			if (i==1 && uwep && (u.umonnum == PM_SUCCUBUS ||
1722 | 				u.umonnum == PM_INCUBUS)) goto use_weapon;
1723 | #endif
1724 | 		case AT_KICK:
1725 | 		case AT_BITE:
1726 | 		case AT_STNG:
1727 | 		case AT_TUCH:
1728 | 		case AT_BUTT:
1729 | 		case AT_TENT:
1730 | 			if (i==0 && uwep && (youmonst.data->mlet==S_LICH)) goto use_weapon;
1731 | 			if ((dhit = (tmp > rnd(20) || u.uswallow)) != 0) {
1732 | 			    int compat;
1733 | 
1734 | 			    if (!u.uswallow &&
1735 | 				(compat=could_seduce(&youmonst, mon, mattk))) {
1736 | 				You("%s %s %s.",
1737 | 				    mon->mcansee && haseyes(mon->data)
1738 | 				    ? "smile at" : "talk to",
1739 | 				    mon_nam(mon),
1740 | 				    compat == 2 ? "engagingly":"seductively");
1741 | 				/* doesn't anger it; no wakeup() */
1742 | 				sum[i] = damageum(mon, mattk);
1743 | 				break;
1744 | 			    }
1745 | 			    wakeup(mon);
1746 | 			    /* maybe this check should be in damageum()? */
1747 | 			    if (mon->data == &mons[PM_SHADE] &&
1748 | 					!(mattk->aatyp == AT_KICK &&
1749 | 					    uarmf && uarmf->blessed)) {
1750 | 				Your("attack passes harmlessly through %s.",
1751 | 				    mon_nam(mon));
1752 | 				break;
1753 | 			    }
1754 | 			    if (mattk->aatyp == AT_KICK)
1755 | 				    You("kick %s.", mon_nam(mon));
1756 | 			    else if (mattk->aatyp == AT_BITE)
1757 | 				    You("bite %s.", mon_nam(mon));
1758 | 			    else if (mattk->aatyp == AT_STNG)
1759 | 				    You("sting %s.", mon_nam(mon));
1760 | 			    else if (mattk->aatyp == AT_BUTT)
1761 | 				    You("butt %s.", mon_nam(mon));
1762 | 			    else if (mattk->aatyp == AT_TUCH)
1763 | 				    You("touch %s.", mon_nam(mon));
1764 | 			    else if (mattk->aatyp == AT_TENT)
1765 | 				    Your("tentacles suck %s.", mon_nam(mon));
1766 | 			    else You("hit %s.", mon_nam(mon));
1767 | 			    sum[i] = damageum(mon, mattk);
1768 | 			} else
1769 | 			    missum(mon, mattk);
1770 | 			break;
1771 | 
1772 | 		case AT_HUGS:
1773 | 			/* automatic if prev two attacks succeed, or if
1774 | 			 * already grabbed in a previous attack
1775 | 			 */
1776 | 			dhit = 1;
1777 | 			wakeup(mon);
1778 | 			if (mon->data == &mons[PM_SHADE])
1779 | 			    Your("hug passes harmlessly through %s.",
1780 | 				mon_nam(mon));
1781 | 			else if (!sticks(mon->data) && !u.uswallow) {
1782 | 			    if (mon==u.ustuck) {
1783 | 				pline("%s is being %s.", Monnam(mon),
1784 | 				    u.umonnum==PM_ROPE_GOLEM ? "choked":
1785 | 				    "crushed");
1786 | 				sum[i] = damageum(mon, mattk);
1787 | 			    } else if(i >= 2 && sum[i-1] && sum[i-2]) {
1788 | 				You("grab %s!", mon_nam(mon));
1789 | 				u.ustuck = mon;
1790 | 				sum[i] = damageum(mon, mattk);
1791 | 			    }
1792 | 			}
1793 | 			break;
1794 | 
1795 | 		case AT_EXPL:	/* automatic hit if next to */
1796 | 			dhit = -1;
1797 | 			wakeup(mon);
1798 | 			sum[i] = explum(mon, mattk);
1799 | 			break;
1800 | 
1801 | 		case AT_ENGL:
1802 | 			if((dhit = (tmp > rnd(20+i)))) {
1803 | 				wakeup(mon);
1804 | 				if (mon->data == &mons[PM_SHADE])
1805 | 				    Your("attempt to surround %s is harmless.",
1806 | 					mon_nam(mon));
1807 | 				else
1808 | 				    sum[i]= gulpum(mon,mattk);
1809 | 			} else
1810 | 				missum(mon, mattk);
1811 | 			break;
1812 | 
1813 | 		case AT_MAGC:
1814 | 			/* No check for uwep; if wielding nothing we want to
1815 | 			 * do the normal 1-2 points bare hand damage...
1816 | 			 */
1817 | 			if (i==0 && (youmonst.data->mlet==S_KOBOLD
1818 | 				|| youmonst.data->mlet==S_ORC
1819 | 				|| youmonst.data->mlet==S_GNOME
1820 | 				)) goto use_weapon;
1821 | 
1822 | 		case AT_NONE:
1823 | 		case AT_BOOM:
1824 | 			continue;
1825 | 			/* Not break--avoid passive attacks from enemy */
1826 | 
1827 | 		case AT_BREA:
1828 | 		case AT_SPIT:
1829 | 		case AT_GAZE:	/* all done using #monster command */
1830 | 			dhit = 0;
1831 | 			break;
1832 | 
1833 | 		default: /* Strange... */
1834 | 			impossible("strange attack of yours (%d)",
1835 | 				 mattk->aatyp);
1836 | 	    }
1837 | 	    if (dhit == -1)
1838 | 		rehumanize();
1839 | 	    if (sum[i] == 2)
1840 | 		return((boolean)passive(mon, 1, 0, mattk->aatyp));
1841 | 							/* defender dead */
1842 | 	    else {
1843 | 		(void) passive(mon, sum[i], 1, mattk->aatyp);
1844 | 		nsum |= sum[i];
1845 | 	    }
1846 | 	    if (!Upolyd)
1847 | 		break; /* No extra attacks if no longer a monster */
1848 | 	    if (multi < 0)
1849 | 		break; /* If paralyzed while attacking, i.e. floating eye */
1850 | 	}
1851 | 	return((boolean)(nsum != 0));
1852 | }
1853 | 
1854 | /*	Special (passive) attacks on you by monsters done here.		*/
1855 | 
1856 | int
1857 | passive(mon, mhit, malive, aatyp)
1858 | register struct monst *mon;
1859 | register boolean mhit;
1860 | register int malive;
1861 | uchar aatyp;
1862 | {
1863 | 	register struct permonst *ptr = mon->data;
1864 | 	register int i, tmp;
1865 | 
1866 | 	for(i = 0; ; i++) {
1867 | 	    if(i >= NATTK) return(malive | mhit);	/* no passive attacks */
1868 | 	    if(ptr->mattk[i].aatyp == AT_NONE) break;	/* try this one */
1869 | 	}
1870 | 	/* Note: tmp not always used */
1871 | 	if (ptr->mattk[i].damn)
1872 | 	    tmp = d((int)ptr->mattk[i].damn, (int)ptr->mattk[i].damd);
1873 | 	else if(ptr->mattk[i].damd)
1874 | 	    tmp = d((int)mon->m_lev+1, (int)ptr->mattk[i].damd);
1875 | 	else
1876 | 	    tmp = 0;
1877 | 
1878 | /*	These affect you even if they just died */
1879 | 
1880 | 	switch(ptr->mattk[i].adtyp) {
1881 | 
1882 | 	  case AD_ACID:
1883 | 	    if(mhit && rn2(2)) {
1884 | 		if (Blind || !flags.verbose) You("are splashed!");
1885 | 		else	You("are splashed by %s acid!",
1886 | 			                s_suffix(mon_nam(mon)));
1887 | 
1888 | 		if (!Acid_resistance)
1889 | 			mdamageu(mon, tmp);
1890 | 		if(!rn2(30)) erode_armor(&youmonst, TRUE);
1891 | 	    }
1892 | 	    if(mhit && !rn2(6)) {
1893 | 		if (aatyp == AT_KICK) {
1894 | 		    if (uarmf)
1895 | 			(void) rust_dmg(uarmf, xname(uarmf), 3, TRUE, &youmonst);
1896 | 		} else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH)
1897 | 		    erode_weapon(uwep, TRUE);
1898 | 	    }
1899 | 	    exercise(A_STR, FALSE);
1900 | 	    break;
1901 | 	  case AD_STON:
1902 | 	    if(mhit) {
1903 | 	      /* mhit does not mean you physically hit; it just means the
1904 | 	         attack was successful */
1905 | 	      if ((aatyp == AT_KICK && !uarmf) ||
1906 | 		    ((aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC
1907 | 				|| aatyp == AT_TUCH) && !uwep && !uarmg) ||
1908 | 		    aatyp == AT_BITE || aatyp == AT_STNG || aatyp == AT_BUTT ||
1909 | 		    aatyp == AT_TENT || aatyp == AT_HUGS || aatyp == AT_ENGL) {
1910 | 		if (!Stone_resistance &&
1911 | 		    !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
1912 | 			You("turn to stone...");
1913 | 			done_in_by(mon);
1914 | 			return 2;
1915 | 		}
1916 | 	      }
1917 | 	    }
1918 | 	    break;
1919 | 	  case AD_RUST:
1920 | 	    if(mhit && !mon->mcan) {
1921 | 	      if (aatyp == AT_KICK) {
1922 | 		if (uarmf)
1923 | 		    (void) rust_dmg(uarmf, xname(uarmf), 1, TRUE, &youmonst);
1924 | 	      } else if (aatyp == AT_WEAP || aatyp == AT_CLAW ||
1925 | 			aatyp == AT_MAGC || aatyp == AT_TUCH)
1926 | 		erode_weapon(uwep, FALSE);
1927 | 	    }
1928 | 	    break;
1929 | 	  case AD_CORRODE:
1930 | 	    if(mhit && !mon->mcan) {
1931 | 	      if (aatyp == AT_KICK) {
1932 | 		if (uarmf)
1933 | 		    (void) rust_dmg(uarmf, xname(uarmf), 3, TRUE, &youmonst);
1934 | 	      } else if (aatyp == AT_WEAP || aatyp == AT_CLAW ||
1935 | 			aatyp == AT_MAGC || aatyp == AT_TUCH)
1936 | 		erode_weapon(uwep, TRUE);
1937 | 	    }
1938 | 	    break;
1939 | 	  case AD_MAGM:
1940 | 	    /* wrath of gods for attacking Oracle */
1941 | 	    if(Antimagic) {
1942 | 		shieldeff(u.ux, u.uy);
1943 | 		pline("A hail of magic missiles narrowly misses you!");
1944 | 	    } else {
1945 | 		You("are hit by magic missiles appearing from thin air!");
1946 | 		mdamageu(mon, tmp);
1947 | 	    }
1948 | 	    break;
1949 | 	  case AD_ENCH:	/* KMH -- remove enchantment (disenchanter) */
1950 | 	    {
1951 | 	  		struct obj *obj = (aatyp == AT_KICK) ? uarmf :
1952 | 	  				uwep ? uwep : uarmg;
1953 | 
1954 | 	    	if (mhit && !mon->mcan && obj) {
1955 | 	    	    if (drain_item(obj) && (obj->known ||
1956 | 	    	    		obj->oclass == ARMOR_CLASS))
1957 | 	    	    	Your("%s less effective.", aobjnam(obj, "seem"));
1958 | 	    	}
1959 | 	    	break;
1960 | 	    }
1961 | 	  default:
1962 | 	    break;
1963 | 	}
1964 | 
1965 | /*	These only affect you if they still live */
1966 | 
1967 | 	if(malive && !mon->mcan && rn2(3)) {
1968 | 
1969 | 	    switch(ptr->mattk[i].adtyp) {
1970 | 
1971 | 	      case AD_PLYS:
1972 | 		if(ptr == &mons[PM_FLOATING_EYE]) {
1973 | 		    if (!canseemon(mon)) {
1974 | 			break;
1975 | 		    }
1976 | 		    if(mon->mcansee) {
1977 | 			if (ureflects("%s gaze is reflected by your %s.",
1978 | 				    s_suffix(Monnam(mon))))
1979 | 			    ;
1980 | 			else if (Free_action)
1981 | 			    You("momentarily stiffen under %s gaze!",
1982 | 				    s_suffix(mon_nam(mon)));
1983 | 			else {
1984 | 			    You("are frozen by %s gaze!",
1985 | 				  s_suffix(mon_nam(mon)));
1986 | 			    nomul((ACURR(A_WIS) > 12 || rn2(4)) ? -tmp : -127);
1987 | 			}
1988 | 		    } else {
1989 | 			pline("%s cannot defend itself.",
1990 | 				Adjmonnam(mon,"blind"));
1991 | 			if(!rn2(500)) change_luck(-1);
1992 | 		    }
1993 | 		} else if (Free_action) {
1994 | 		    You("momentarily stiffen.");
1995 | 		} else { /* gelatinous cube */
1996 | 		    You("are frozen by %s!", mon_nam(mon));
1997 | 		    nomul(-tmp);
1998 | 		    exercise(A_DEX, FALSE);
1999 | 		}
2000 | 		break;
2001 | 	      case AD_COLD:		/* brown mold or blue jelly */
2002 | 		if(monnear(mon, u.ux, u.uy)) {
2003 | 		    if(Cold_resistance) {
2004 | 			shieldeff(u.ux, u.uy);
2005 | 			You_feel("a mild chill.");
2006 | 			ugolemeffects(AD_COLD, tmp);
2007 | 			break;
2008 | 		    }
2009 | 		    You("are suddenly very cold!");
2010 | 		    mdamageu(mon, tmp);
2011 | 		/* monster gets stronger with your heat! */
2012 | 		    mon->mhp += tmp / 2;
2013 | 		    if (mon->mhpmax < mon->mhp) mon->mhpmax = mon->mhp;
2014 | 		/* at a certain point, the monster will reproduce! */
2015 | 		    if(mon->mhpmax > ((int) (mon->m_lev+1) * 8))
2016 | 			(void)split_mon(mon, &youmonst);
2017 | 		}
2018 | 		break;
2019 | 	      case AD_STUN:		/* specifically yellow mold */
2020 | 		if(!Stunned)
2021 | 		    make_stunned((long)tmp, TRUE);
2022 | 		break;
2023 | 	      case AD_FIRE:
2024 | 		if(monnear(mon, u.ux, u.uy)) {
2025 | 		    if(Fire_resistance) {
2026 | 			shieldeff(u.ux, u.uy);
2027 | 			You_feel("mildly warm.");
2028 | 			ugolemeffects(AD_FIRE, tmp);
2029 | 			break;
2030 | 		    }
2031 | 		    You("are suddenly very hot!");
2032 | 		    mdamageu(mon, tmp);
2033 | 		}
2034 | 		break;
2035 | 	      case AD_ELEC:
2036 | 		if(Shock_resistance) {
2037 | 		    shieldeff(u.ux, u.uy);
2038 | 		    You_feel("a mild tingle.");
2039 | 		    ugolemeffects(AD_ELEC, tmp);
2040 | 		    break;
2041 | 		}
2042 | 		You("are jolted with electricity!");
2043 | 		mdamageu(mon, tmp);
2044 | 		break;
2045 | 	      default:
2046 | 		break;
2047 | 	    }
2048 | 	}
2049 | 	return(malive | mhit);
2050 | }
2051 | 
2052 | /* Note: caller must ascertain mtmp is mimicking... */
2053 | void
2054 | stumble_onto_mimic(mtmp)
2055 | struct monst *mtmp;
2056 | {
2057 | 	const char *fmt = "Wait!  That's %s!",
2058 | 		   *generic = "a monster",
2059 | 		   *what = 0;
2060 | 
2061 | 	if(!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data,AD_STCK))
2062 | 	    u.ustuck = mtmp;
2063 | 
2064 | 	if (Blind) {
2065 | 	    if (!Blind_telepat)
2066 | 		what = generic;		/* with default fmt */
2067 | 	    else if (mtmp->m_ap_type == M_AP_MONSTER)
2068 | 		what = a_monnam(mtmp);	/* differs from what was sensed */
2069 | 	} else {
2070 | 	    int glyph = levl[u.ux+u.dx][u.uy+u.dy].glyph;
2071 | 
2072 | 	    if (glyph_is_cmap(glyph) &&
2073 | 		    (glyph_to_cmap(glyph) == S_hcdoor ||
2074 | 		     glyph_to_cmap(glyph) == S_vcdoor))
2075 | 		fmt = "The door actually was %s!";
2076 | 	    else if (glyph_is_object(glyph) &&
2077 | 		    glyph_to_obj(glyph) == GOLD_PIECE)
2078 | 		fmt = "That gold was %s!";
2079 | 
2080 | 	    /* cloned Wiz starts out mimicking some other monster and
2081 | 	       might make himself invisible before being revealed */
2082 | 	    if (mtmp->minvis && !See_invisible)
2083 | 		what = generic;
2084 | 	    else
2085 | 		what = a_monnam(mtmp);
2086 | 	}
2087 | 	if (what) pline(fmt, what);
2088 | 
2089 | 	wakeup(mtmp);	/* clears mimicking */
2090 | }
2091 | 
2092 | STATIC_OVL void
2093 | nohandglow(mon)
2094 | struct monst *mon;
2095 | {
2096 | 	char *hands=makeplural(body_part(HAND));
2097 | 
2098 | 	if (!u.umconf || mon->mconf) return;
2099 | 	if (u.umconf == 1) {
2100 | 		if (Blind)
2101 | 			Your("%s stop tingling.", hands);
2102 | 		else
2103 | 			Your("%s stop glowing %s.", hands, hcolor(red));
2104 | 	} else {
2105 | 		if (Blind)
2106 | 			pline_The("tingling in your %s lessens.", hands);
2107 | 		else
2108 | 			Your("%s no longer glow so brightly %s.", hands,
2109 | 				hcolor(red));
2110 | 	}
2111 | 	u.umconf--;
2112 | }
2113 | 
2114 | int
2115 | flash_hits_mon(mtmp, otmp)
2116 | struct monst *mtmp;
2117 | struct obj *otmp;	/* source of flash */
2118 | {
2119 | 	int tmp, amt, res = 0, useeit = canseemon(mtmp);
2120 | 
2121 | 	if (mtmp->msleeping) {
2122 | 	    mtmp->msleeping = 0;
2123 | 	    if (useeit) {
2124 | 		pline_The("flash awakens %s.", mon_nam(mtmp));
2125 | 		res = 1;
2126 | 	    }
2127 | 	} else if (mtmp->data->mlet != S_LIGHT) {
2128 | 	    if (!resists_blnd(mtmp)) {
2129 | 		tmp = dist2(otmp->ox, otmp->oy, mtmp->mx, mtmp->my);
2130 | 		if (useeit) {
2131 | 		    pline("%s is blinded by the flash!", Monnam(mtmp));
2132 | 		    res = 1;
2133 | 		}
2134 | 		if (mtmp->data == &mons[PM_GREMLIN]) {
2135 | 		    /* Rule #1: Keep them out of the light. */
2136 | 		    amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4) :
2137 | 		          rn2(min(mtmp->mhp,4));
2138 | 		    pline("%s %s!", Monnam(mtmp), amt > mtmp->mhp / 2 ?
2139 | 			  "wails in agony" : "cries out in pain");
2140 | 		    if ((mtmp->mhp -= amt) <= 0) {
2141 | 			if (flags.mon_moving)
2142 | 			    monkilled(mtmp, (char *)0, AD_BLND);
2143 | 			else
2144 | 			    killed(mtmp);
2145 | 		    } else if (cansee(mtmp->mx,mtmp->my) && !canspotmon(mtmp)){
2146 | 			map_invisible(mtmp->mx, mtmp->my);
2147 | 		    }
2148 | 		}
2149 | 		if (mtmp->mhp > 0) {
2150 | 		    if (!flags.mon_moving) setmangry(mtmp);
2151 | 		    if (tmp < 9 && !mtmp->isshk && rn2(4)) {
2152 | 			mtmp->mflee = 1;
2153 | 			if (rn2(4)) mtmp->mfleetim = rnd(100);
2154 | 		    }
2155 | 		    mtmp->mcansee = 0;
2156 | 		    mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50/tmp);
2157 | 		}
2158 | 	    }
2159 | 	}
2160 | 	return res;
2161 | }
2162 | 
2163 | /*uhitm.c*/