OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / src / uhitm.c
1 /* NetHack 3.6  uhitm.c $NHDT-Date: 1446887537 2015/11/07 09:12:17 $  $NHDT-Branch: master $:$NHDT-Revision: 1.151 $ */
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 *, struct obj *, int *,
8                                        int, int, struct attack *));
9 STATIC_DCL boolean FDECL(theft_petrifies, (struct obj *));
10 STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *));
11 STATIC_DCL boolean FDECL(hitum, (struct monst *, struct attack *));
12 STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *, struct obj *, int));
13 STATIC_DCL int FDECL(joust, (struct monst *, struct obj *));
14 STATIC_DCL void NDECL(demonpet);
15 STATIC_DCL boolean FDECL(m_slips_free, (struct monst * mtmp,
16                                         struct attack *mattk));
17 STATIC_DCL int FDECL(explum, (struct monst *, struct attack *));
18 STATIC_DCL void FDECL(start_engulf, (struct monst *));
19 STATIC_DCL void NDECL(end_engulf);
20 STATIC_DCL int FDECL(gulpum, (struct monst *, struct attack *));
21 STATIC_DCL boolean FDECL(hmonas, (struct monst *));
22 STATIC_DCL void FDECL(nohandglow, (struct monst *));
23 STATIC_DCL boolean FDECL(shade_aware, (struct obj *));
24
25 extern boolean notonhead; /* for long worms */
26 /* The below might become a parameter instead if we use it a lot */
27 static int dieroll;
28 /* Used to flag attacks caused by Stormbringer's maliciousness. */
29 static boolean override_confirmation = FALSE;
30
31 #define PROJECTILE(obj) ((obj) && is_ammo(obj))
32
33 void
34 erode_armor(mdef, hurt)
35 struct monst *mdef;
36 int hurt;
37 {
38     struct obj *target;
39
40     /* What the following code does: it keeps looping until it
41      * finds a target for the rust monster.
42      * Head, feet, etc... not covered by metal, or covered by
43      * rusty metal, are not targets.  However, your body always
44      * is, no matter what covers it.
45      */
46     while (1) {
47         switch (rn2(5)) {
48         case 0:
49             target = which_armor(mdef, W_ARMH);
50             if (!target
51                 || erode_obj(target, xname(target), hurt, EF_GREASE)
52                        == ER_NOTHING)
53                 continue;
54             break;
55         case 1:
56             target = which_armor(mdef, W_ARMC);
57             if (target) {
58                 (void) erode_obj(target, xname(target), hurt,
59                                  EF_GREASE | EF_VERBOSE);
60                 break;
61             }
62             if ((target = which_armor(mdef, W_ARM)) != (struct obj *) 0) {
63                 (void) erode_obj(target, xname(target), hurt,
64                                  EF_GREASE | EF_VERBOSE);
65             } else if ((target = which_armor(mdef, W_ARMU))
66                        != (struct obj *) 0) {
67                 (void) erode_obj(target, xname(target), hurt,
68                                  EF_GREASE | EF_VERBOSE);
69             }
70             break;
71         case 2:
72             target = which_armor(mdef, W_ARMS);
73             if (!target
74                 || erode_obj(target, xname(target), hurt, EF_GREASE)
75                        == ER_NOTHING)
76                 continue;
77             break;
78         case 3:
79             target = which_armor(mdef, W_ARMG);
80             if (!target
81                 || erode_obj(target, xname(target), hurt, EF_GREASE)
82                        == ER_NOTHING)
83                 continue;
84             break;
85         case 4:
86             target = which_armor(mdef, W_ARMF);
87             if (!target
88                 || erode_obj(target, xname(target), hurt, EF_GREASE)
89                        == ER_NOTHING)
90                 continue;
91             break;
92         }
93         break; /* Out of while loop */
94     }
95 }
96
97 /* FALSE means it's OK to attack */
98 boolean
99 attack_checks(mtmp, wep)
100 register struct monst *mtmp;
101 struct obj *wep; /* uwep for attack(), null for kick_monster() */
102 {
103     char qbuf[QBUFSZ];
104
105     /* if you're close enough to attack, alert any waiting monster */
106     mtmp->mstrategy &= ~STRAT_WAITMASK;
107
108     if (u.uswallow && mtmp == u.ustuck)
109         return FALSE;
110
111     if (context.forcefight) {
112         /* Do this in the caller, after we checked that the monster
113          * didn't die from the blow.  Reason: putting the 'I' there
114          * causes the hero to forget the square's contents since
115          * both 'I' and remembered contents are stored in .glyph.
116          * If the monster dies immediately from the blow, the 'I' will
117          * not stay there, so the player will have suddenly forgotten
118          * the square's contents for no apparent reason.
119         if (!canspotmon(mtmp)
120             && !glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph))
121             map_invisible(bhitpos.x, bhitpos.y);
122          */
123         return FALSE;
124     }
125
126     /* Put up an invisible monster marker, but with exceptions for
127      * monsters that hide and monsters you've been warned about.
128      * The former already prints a warning message and
129      * prevents you from hitting the monster just via the hidden monster
130      * code below; if we also did that here, similar behavior would be
131      * happening two turns in a row.  The latter shows a glyph on
132      * the screen, so you know something is there.
133      */
134     if (!canspotmon(mtmp) && !glyph_is_warning(glyph_at(bhitpos.x, bhitpos.y))
135         && !glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)
136         && !(!Blind && mtmp->mundetected && hides_under(mtmp->data))) {
137         pline("Wait!  There's %s there you can't see!", something);
138         map_invisible(bhitpos.x, bhitpos.y);
139         /* if it was an invisible mimic, treat it as if we stumbled
140          * onto a visible mimic
141          */
142         if (mtmp->m_ap_type && !Protection_from_shape_changers
143             /* applied pole-arm attack is too far to get stuck */
144             && distu(mtmp->mx, mtmp->my) <= 2) {
145             if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK))
146                 u.ustuck = mtmp;
147         }
148         wakeup(mtmp); /* always necessary; also un-mimics mimics */
149         return TRUE;
150     }
151
152     if (mtmp->m_ap_type && !Protection_from_shape_changers && !sensemon(mtmp)
153         && !glyph_is_warning(glyph_at(bhitpos.x, bhitpos.y))) {
154         /* If a hidden mimic was in a square where a player remembers
155          * some (probably different) unseen monster, the player is in
156          * luck--he attacks it even though it's hidden.
157          */
158         if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) {
159             seemimic(mtmp);
160             return FALSE;
161         }
162         stumble_onto_mimic(mtmp);
163         return TRUE;
164     }
165
166     if (mtmp->mundetected && !canseemon(mtmp)
167         && !glyph_is_warning(glyph_at(bhitpos.x, bhitpos.y))
168         && (hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)) {
169         mtmp->mundetected = mtmp->msleeping = 0;
170         newsym(mtmp->mx, mtmp->my);
171         if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) {
172             seemimic(mtmp);
173             return FALSE;
174         }
175         if (!((Blind ? Blind_telepat : Unblind_telepat) || Detect_monsters)) {
176             struct obj *obj;
177
178             if (Blind || (is_pool(mtmp->mx, mtmp->my) && !Underwater))
179                 pline("Wait!  There's a hidden monster there!");
180             else if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0)
181                 pline("Wait!  There's %s hiding under %s!",
182                       an(l_monnam(mtmp)), doname(obj));
183             return TRUE;
184         }
185     }
186
187     /*
188      * make sure to wake up a monster from the above cases if the
189      * hero can sense that the monster is there.
190      */
191     if ((mtmp->mundetected || mtmp->m_ap_type) && sensemon(mtmp)) {
192         mtmp->mundetected = 0;
193         wakeup(mtmp);
194     }
195
196     if (flags.confirm && mtmp->mpeaceful && !Confusion && !Hallucination
197         && !Stunned) {
198         /* Intelligent chaotic weapons (Stormbringer) want blood */
199         if (wep && wep->oartifact == ART_STORMBRINGER) {
200             override_confirmation = TRUE;
201             return FALSE;
202         }
203         if (canspotmon(mtmp)) {
204             Sprintf(qbuf, "Really attack %s?", mon_nam(mtmp));
205             if (!paranoid_query(ParanoidHit, qbuf)) {
206                 context.move = 0;
207                 return TRUE;
208             }
209         }
210     }
211
212     return FALSE;
213 }
214
215 /*
216  * It is unchivalrous for a knight to attack the defenseless or from behind.
217  */
218 void
219 check_caitiff(mtmp)
220 struct monst *mtmp;
221 {
222     if (u.ualign.record <= -10)
223         return;
224
225     if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL
226         && (!mtmp->mcanmove || mtmp->msleeping
227             || (mtmp->mflee && !mtmp->mavenge))) {
228         You("caitiff!");
229         adjalign(-1);
230     } else if (Role_if(PM_SAMURAI) && mtmp->mpeaceful) {
231         /* attacking peaceful creatures is bad for the samurai's giri */
232         You("dishonorably attack the innocent!");
233         adjalign(-1);
234     }
235 }
236
237 int
238 find_roll_to_hit(mtmp, aatyp, weapon, attk_count, role_roll_penalty)
239 register struct monst *mtmp;
240 uchar aatyp;        /* usually AT_WEAP or AT_KICK */
241 struct obj *weapon; /* uwep or uswapwep or NULL */
242 int *attk_count, *role_roll_penalty;
243 {
244     int tmp, tmp2;
245
246     *role_roll_penalty = 0; /* default is `none' */
247
248     tmp = 1 + Luck + abon() + find_mac(mtmp) + u.uhitinc
249           + maybe_polyd(youmonst.data->mlevel, u.ulevel);
250
251     /* some actions should occur only once during multiple attacks */
252     if (!(*attk_count)++) {
253         /* knight's chivalry or samurai's giri */
254         check_caitiff(mtmp);
255     }
256
257     /* adjust vs. (and possibly modify) monster state */
258     if (mtmp->mstun)
259         tmp += 2;
260     if (mtmp->mflee)
261         tmp += 2;
262
263     if (mtmp->msleeping) {
264         mtmp->msleeping = 0;
265         tmp += 2;
266     }
267     if (!mtmp->mcanmove) {
268         tmp += 4;
269         if (!rn2(10)) {
270             mtmp->mcanmove = 1;
271             mtmp->mfrozen = 0;
272         }
273     }
274
275     /* role/race adjustments */
276     if (Role_if(PM_MONK) && !Upolyd) {
277         if (uarm)
278             tmp -= (*role_roll_penalty = urole.spelarmr);
279         else if (!uwep && !uarms)
280             tmp += (u.ulevel / 3) + 2;
281     }
282     if (is_orc(mtmp->data)
283         && maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF)))
284         tmp++;
285
286     /* encumbrance: with a lot of luggage, your agility diminishes */
287     if ((tmp2 = near_capacity()) != 0)
288         tmp -= (tmp2 * 2) - 1;
289     if (u.utrap)
290         tmp -= 3;
291
292     /*
293      * hitval applies if making a weapon attack while wielding a weapon;
294      * weapon_hit_bonus applies if doing a weapon attack even bare-handed
295      * or if kicking as martial artist
296      */
297     if (aatyp == AT_WEAP || aatyp == AT_CLAW) {
298         if (weapon)
299             tmp += hitval(weapon, mtmp);
300         tmp += weapon_hit_bonus(weapon);
301     } else if (aatyp == AT_KICK && martial_bonus()) {
302         tmp += weapon_hit_bonus((struct obj *) 0);
303     }
304
305     return tmp;
306 }
307
308 /* try to attack; return False if monster evaded;
309    u.dx and u.dy must be set */
310 boolean
311 attack(mtmp)
312 register struct monst *mtmp;
313 {
314     register struct permonst *mdat = mtmp->data;
315
316     /* This section of code provides protection against accidentally
317      * hitting peaceful (like '@') and tame (like 'd') monsters.
318      * Protection is provided as long as player is not: blind, confused,
319      * hallucinating or stunned.
320      * changes by wwp 5/16/85
321      * More changes 12/90, -dkh-. if its tame and safepet, (and protected
322      * 07/92) then we assume that you're not trying to attack. Instead,
323      * you'll usually just swap places if this is a movement command
324      */
325     /* Intelligent chaotic weapons (Stormbringer) want blood */
326     if (is_safepet(mtmp) && !context.forcefight) {
327         if (!uwep || uwep->oartifact != ART_STORMBRINGER) {
328             /* there are some additional considerations: this won't work
329              * if in a shop or Punished or you miss a random roll or
330              * if you can walk thru walls and your pet cannot (KAA) or
331              * if your pet is a long worm (unless someone does better).
332              * there's also a chance of displacing a "frozen" monster.
333              * sleeping monsters might magically walk in their sleep.
334              */
335             boolean foo = (Punished || !rn2(7) || is_longworm(mtmp->data)),
336                     inshop = FALSE;
337             char *p;
338
339             for (p = in_rooms(mtmp->mx, mtmp->my, SHOPBASE); *p; p++)
340                 if (tended_shop(&rooms[*p - ROOMOFFSET])) {
341                     inshop = TRUE;
342                     break;
343                 }
344
345             if (inshop || foo || (IS_ROCK(levl[u.ux][u.uy].typ)
346                                   && !passes_walls(mtmp->data))) {
347                 char buf[BUFSZ];
348
349                 monflee(mtmp, rnd(6), FALSE, FALSE);
350                 Strcpy(buf, y_monnam(mtmp));
351                 buf[0] = highc(buf[0]);
352                 You("stop.  %s is in the way!", buf);
353                 return TRUE;
354             } else if ((mtmp->mfrozen || (!mtmp->mcanmove)
355                         || (mtmp->data->mmove == 0)) && rn2(6)) {
356                 pline("%s doesn't seem to move!", Monnam(mtmp));
357                 return TRUE;
358             } else
359                 return FALSE;
360         }
361     }
362
363     /* possibly set in attack_checks;
364        examined in known_hitum, called via hitum or hmonas below */
365     override_confirmation = FALSE;
366     /* attack_checks() used to use <u.ux+u.dx,u.uy+u.dy> directly, now
367        it uses bhitpos instead; it might map an invisible monster there */
368     bhitpos.x = u.ux + u.dx;
369     bhitpos.y = u.uy + u.dy;
370     if (attack_checks(mtmp, uwep))
371         return TRUE;
372
373     if (Upolyd && noattacks(youmonst.data)) {
374         /* certain "pacifist" monsters don't attack */
375         You("have no way to attack monsters physically.");
376         mtmp->mstrategy &= ~STRAT_WAITMASK;
377         goto atk_done;
378     }
379
380     if (check_capacity("You cannot fight while so heavily loaded.")
381         /* consume extra nutrition during combat; maybe pass out */
382         || overexertion())
383         goto atk_done;
384
385     if (u.twoweap && !can_twoweapon())
386         untwoweapon();
387
388     if (unweapon) {
389         unweapon = FALSE;
390         if (flags.verbose) {
391             if (uwep)
392                 You("begin bashing monsters with %s.",
393                     yobjnam(uwep, (char *) 0));
394             else if (!cantwield(youmonst.data))
395                 You("begin %sing monsters with your %s %s.",
396                     Role_if(PM_MONK) ? "strik" : "bash",
397                     uarmg ? "gloved" : "bare", /* Del Lamb */
398                     makeplural(body_part(HAND)));
399         }
400     }
401     exercise(A_STR, TRUE); /* you're exercising muscles */
402     /* andrew@orca: prevent unlimited pick-axe attacks */
403     u_wipe_engr(3);
404
405     /* Is the "it died" check actually correct? */
406     if (mdat->mlet == S_LEPRECHAUN && !mtmp->mfrozen && !mtmp->msleeping
407         && !mtmp->mconf && mtmp->mcansee && !rn2(7)
408         && (m_move(mtmp, 0) == 2 /* it died */
409             || mtmp->mx != u.ux + u.dx
410             || mtmp->my != u.uy + u.dy)) /* it moved */
411         return FALSE;
412
413     if (Upolyd)
414         (void) hmonas(mtmp);
415     else
416         (void) hitum(mtmp, youmonst.data->mattk);
417     mtmp->mstrategy &= ~STRAT_WAITMASK;
418
419 atk_done:
420     /* see comment in attack_checks() */
421     /* we only need to check for this if we did an attack_checks()
422      * and it returned 0 (it's okay to attack), and the monster didn't
423      * evade.
424      */
425     if (context.forcefight && mtmp->mhp > 0 && !canspotmon(mtmp)
426         && !glyph_is_invisible(levl[u.ux + u.dx][u.uy + u.dy].glyph)
427         && !(u.uswallow && mtmp == u.ustuck))
428         map_invisible(u.ux + u.dx, u.uy + u.dy);
429
430     return TRUE;
431 }
432
433 /* really hit target monster; returns TRUE if it still lives */
434 STATIC_OVL boolean
435 known_hitum(mon, weapon, mhit, rollneeded, armorpenalty, uattk)
436 register struct monst *mon;
437 struct obj *weapon;
438 int *mhit;
439 int rollneeded, armorpenalty; /* for monks */
440 struct attack *uattk;
441 {
442     register boolean malive = TRUE;
443
444     if (override_confirmation) {
445         /* this may need to be generalized if weapons other than
446            Stormbringer acquire similar anti-social behavior... */
447         if (flags.verbose)
448             Your("bloodthirsty blade attacks!");
449     }
450
451     if (!*mhit) {
452         missum(mon, uattk, (rollneeded + armorpenalty > dieroll));
453     } else {
454         int oldhp = mon->mhp, x = u.ux + u.dx, y = u.uy + u.dy;
455         long oldweaphit = u.uconduct.weaphit;
456
457         /* KMH, conduct */
458         if (weapon && (weapon->oclass == WEAPON_CLASS || is_weptool(weapon)))
459             u.uconduct.weaphit++;
460
461         /* we hit the monster; be careful: it might die or
462            be knocked into a different location */
463         notonhead = (mon->mx != x || mon->my != y);
464         malive = hmon(mon, weapon, HMON_MELEE);
465         if (malive) {
466             /* monster still alive */
467             if (!rn2(25) && mon->mhp < mon->mhpmax / 2
468                 && !(u.uswallow && mon == u.ustuck)) {
469                 /* maybe should regurgitate if swallowed? */
470                 monflee(mon, !rn2(3) ? rnd(100) : 0, FALSE, TRUE);
471
472                 if (u.ustuck == mon && !u.uswallow && !sticks(youmonst.data))
473                     u.ustuck = 0;
474             }
475             /* Vorpal Blade hit converted to miss */
476             /* could be headless monster or worm tail */
477             if (mon->mhp == oldhp) {
478                 *mhit = 0;
479                 /* a miss does not break conduct */
480                 u.uconduct.weaphit = oldweaphit;
481             }
482             if (mon->wormno && *mhit)
483                 cutworm(mon, x, y, weapon);
484         }
485     }
486     return malive;
487 }
488
489 /* hit target monster; returns TRUE if it still lives */
490 STATIC_OVL boolean
491 hitum(mon, uattk)
492 struct monst *mon;
493 struct attack *uattk;
494 {
495     boolean malive, wep_was_destroyed = FALSE;
496     struct obj *wepbefore = uwep;
497     int armorpenalty, attknum = 0, x = u.ux + u.dx, y = u.uy + u.dy,
498                       tmp = find_roll_to_hit(mon, uattk->aatyp, uwep,
499                                              &attknum, &armorpenalty);
500     int mhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
501
502     if (tmp > dieroll)
503         exercise(A_DEX, TRUE);
504     malive = known_hitum(mon, uwep, &mhit, tmp, armorpenalty, uattk);
505     /* second attack for two-weapon combat; won't occur if Stormbringer
506        overrode confirmation (assumes Stormbringer is primary weapon)
507        or if the monster was killed or knocked to different location */
508     if (u.twoweap && !override_confirmation && malive && m_at(x, y) == mon) {
509         tmp = find_roll_to_hit(mon, uattk->aatyp, uswapwep, &attknum,
510                                &armorpenalty);
511         mhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
512         malive = known_hitum(mon, uswapwep, &mhit, tmp, armorpenalty, uattk);
513     }
514     if (wepbefore && !uwep)
515         wep_was_destroyed = TRUE;
516     (void) passive(mon, mhit, malive, AT_WEAP, wep_was_destroyed);
517     return malive;
518 }
519
520 /* general "damage monster" routine; return True if mon still alive */
521 boolean
522 hmon(mon, obj, thrown)
523 struct monst *mon;
524 struct obj *obj;
525 int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
526 {
527     boolean result, anger_guards;
528
529     anger_guards = (mon->mpeaceful
530                     && (mon->ispriest || mon->isshk || is_watch(mon->data)));
531     result = hmon_hitmon(mon, obj, thrown);
532     if (mon->ispriest && !rn2(2))
533         ghod_hitsu(mon);
534     if (anger_guards)
535         (void) angry_guards(!!Deaf);
536     return result;
537 }
538
539 /* guts of hmon() */
540 STATIC_OVL boolean
541 hmon_hitmon(mon, obj, thrown)
542 struct monst *mon;
543 struct obj *obj;
544 int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
545 {
546     int tmp;
547     struct permonst *mdat = mon->data;
548     int barehand_silver_rings = 0;
549     /* The basic reason we need all these booleans is that we don't want
550      * a "hit" message when a monster dies, so we have to know how much
551      * damage it did _before_ outputting a hit message, but any messages
552      * associated with the damage don't come out until _after_ outputting
553      * a hit message.
554      */
555     boolean hittxt = FALSE, destroyed = FALSE, already_killed = FALSE;
556     boolean get_dmg_bonus = TRUE;
557     boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE,
558             unpoisonmsg = FALSE;
559     boolean silvermsg = FALSE, silverobj = FALSE;
560     boolean valid_weapon_attack = FALSE;
561     boolean unarmed = !uwep && !uarm && !uarms;
562     boolean hand_to_hand = (thrown == HMON_MELEE
563                             /* not grapnels; applied implies uwep */
564                             || (thrown == HMON_APPLIED && is_pole(uwep)));
565     int jousting = 0;
566     int wtype;
567     struct obj *monwep;
568     char unconventional[BUFSZ]; /* substituted for word "attack" in msg */
569     char saved_oname[BUFSZ];
570
571     unconventional[0] = '\0';
572     saved_oname[0] = '\0';
573
574     wakeup(mon);
575     if (!obj) { /* attack with bare hands */
576         if (mdat == &mons[PM_SHADE])
577             tmp = 0;
578         else if (martial_bonus())
579             tmp = rnd(4); /* bonus for martial arts */
580         else
581             tmp = rnd(2);
582         valid_weapon_attack = (tmp > 1);
583         /* blessed gloves give bonuses when fighting 'bare-handed' */
584         if (uarmg && uarmg->blessed
585             && (is_undead(mdat) || is_demon(mdat) || is_vampshifter(mon)))
586             tmp += rnd(4);
587         /* So do silver rings.  Note: rings are worn under gloves, so you
588          * don't get both bonuses.
589          */
590         if (!uarmg) {
591             if (uleft && objects[uleft->otyp].oc_material == SILVER)
592                 barehand_silver_rings++;
593             if (uright && objects[uright->otyp].oc_material == SILVER)
594                 barehand_silver_rings++;
595             if (barehand_silver_rings && mon_hates_silver(mon)) {
596                 tmp += rnd(20);
597                 silvermsg = TRUE;
598             }
599         }
600     } else {
601         Strcpy(saved_oname, cxname(obj));
602         if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
603             || obj->oclass == GEM_CLASS) {
604             /* is it not a melee weapon? */
605             if (/* if you strike with a bow... */
606                 is_launcher(obj)
607                 /* or strike with a missile in your hand... */
608                 || (!thrown && (is_missile(obj) || is_ammo(obj)))
609                 /* or use a pole at short range and not mounted... */
610                 || (!thrown && !u.usteed && is_pole(obj))
611                 /* or throw a missile without the proper bow... */
612                 || (is_ammo(obj) && (thrown != HMON_THROWN
613                                      || !ammo_and_launcher(obj, uwep)))) {
614                 /* then do only 1-2 points of damage */
615                 if (mdat == &mons[PM_SHADE] && !shade_glare(obj))
616                     tmp = 0;
617                 else
618                     tmp = rnd(2);
619                 if (objects[obj->otyp].oc_material == SILVER
620                     && mon_hates_silver(mon)) {
621                     silvermsg = TRUE;
622                     silverobj = TRUE;
623                     /* if it will already inflict dmg, make it worse */
624                     tmp += rnd((tmp) ? 20 : 10);
625                 }
626                 if (!thrown && obj == uwep && obj->otyp == BOOMERANG
627                     && rnl(4) == 4 - 1) {
628                     boolean more_than_1 = (obj->quan > 1L);
629
630                     pline("As you hit %s, %s%s breaks into splinters.",
631                           mon_nam(mon), more_than_1 ? "one of " : "",
632                           yname(obj));
633                     if (!more_than_1)
634                         uwepgone(); /* set unweapon */
635                     useup(obj);
636                     if (!more_than_1)
637                         obj = (struct obj *) 0;
638                     hittxt = TRUE;
639                     if (mdat != &mons[PM_SHADE])
640                         tmp++;
641                 }
642             } else {
643                 tmp = dmgval(obj, mon);
644                 /* a minimal hit doesn't exercise proficiency */
645                 valid_weapon_attack = (tmp > 1);
646                 if (!valid_weapon_attack || mon == u.ustuck || u.twoweap) {
647                     ; /* no special bonuses */
648                 } else if (mon->mflee && Role_if(PM_ROGUE) && !Upolyd
649                            /* multi-shot throwing is too powerful here */
650                            && hand_to_hand) {
651                     You("strike %s from behind!", mon_nam(mon));
652                     tmp += rnd(u.ulevel);
653                     hittxt = TRUE;
654                 } else if (dieroll == 2 && obj == uwep
655                            && obj->oclass == WEAPON_CLASS
656                            && (bimanual(obj)
657                                || (Role_if(PM_SAMURAI) && obj->otyp == KATANA
658                                    && !uarms))
659                            && ((wtype = uwep_skill_type()) != P_NONE
660                                && P_SKILL(wtype) >= P_SKILLED)
661                            && ((monwep = MON_WEP(mon)) != 0
662                                && !is_flimsy(monwep)
663                                && !obj_resists(
664                                       monwep, 50 + 15 * greatest_erosion(obj),
665                                       100))) {
666                     /*
667                      * 2.5% chance of shattering defender's weapon when
668                      * using a two-handed weapon; less if uwep is rusted.
669                      * [dieroll == 2 is most successful non-beheading or
670                      * -bisecting hit, in case of special artifact damage;
671                      * the percentage chance is (1/20)*(50/100).]
672                      */
673                     setmnotwielded(mon, monwep);
674                     mon->weapon_check = NEED_WEAPON;
675                     pline("%s from the force of your blow!",
676                           Yobjnam2(monwep, "shatter"));
677                     m_useupall(mon, monwep);
678                     /* If someone just shattered MY weapon, I'd flee! */
679                     if (rn2(4)) {
680                         monflee(mon, d(2, 3), TRUE, TRUE);
681                     }
682                     hittxt = TRUE;
683                 }
684
685                 if (obj->oartifact
686                     && artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) {
687                     if (mon->mhp <= 0) /* artifact killed monster */
688                         return FALSE;
689                     if (tmp == 0)
690                         return TRUE;
691                     hittxt = TRUE;
692                 }
693                 if (objects[obj->otyp].oc_material == SILVER
694                     && mon_hates_silver(mon)) {
695                     silvermsg = TRUE;
696                     silverobj = TRUE;
697                 }
698                 if (u.usteed && !thrown && tmp > 0
699                     && weapon_type(obj) == P_LANCE && mon != u.ustuck) {
700                     jousting = joust(mon, obj);
701                     /* exercise skill even for minimal damage hits */
702                     if (jousting)
703                         valid_weapon_attack = TRUE;
704                 }
705                 if (thrown == HMON_THROWN
706                     && (is_ammo(obj) || is_missile(obj))) {
707                     if (ammo_and_launcher(obj, uwep)) {
708                         /* Elves and Samurai do extra damage using
709                          * their bows&arrows; they're highly trained.
710                          */
711                         if (Role_if(PM_SAMURAI) && obj->otyp == YA
712                             && uwep->otyp == YUMI)
713                             tmp++;
714                         else if (Race_if(PM_ELF) && obj->otyp == ELVEN_ARROW
715                                  && uwep->otyp == ELVEN_BOW)
716                             tmp++;
717                     }
718                     if (obj->opoisoned && is_poisonable(obj))
719                         ispoisoned = TRUE;
720                 }
721             }
722         } else if (obj->oclass == POTION_CLASS) {
723             if (obj->quan > 1L)
724                 obj = splitobj(obj, 1L);
725             else
726                 setuwep((struct obj *) 0);
727             freeinv(obj);
728             potionhit(mon, obj, TRUE);
729             if (mon->mhp <= 0)
730                 return FALSE; /* killed */
731             hittxt = TRUE;
732             /* in case potion effect causes transformation */
733             mdat = mon->data;
734             tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1;
735         } else {
736             if (mdat == &mons[PM_SHADE] && !shade_aware(obj)) {
737                 tmp = 0;
738                 Strcpy(unconventional, cxname(obj));
739             } else {
740                 switch (obj->otyp) {
741                 case BOULDER:         /* 1d20 */
742                 case HEAVY_IRON_BALL: /* 1d25 */
743                 case IRON_CHAIN:      /* 1d4+1 */
744                     tmp = dmgval(obj, mon);
745                     break;
746                 case MIRROR:
747                     if (breaktest(obj)) {
748                         You("break %s.  That's bad luck!", ysimple_name(obj));
749                         change_luck(-2);
750                         useup(obj);
751                         obj = (struct obj *) 0;
752                         unarmed = FALSE; /* avoid obj==0 confusion */
753                         get_dmg_bonus = FALSE;
754                         hittxt = TRUE;
755                     }
756                     tmp = 1;
757                     break;
758                 case EXPENSIVE_CAMERA:
759                     You("succeed in destroying %s.  Congratulations!",
760                         ysimple_name(obj));
761                     release_camera_demon(obj, u.ux, u.uy);
762                     useup(obj);
763                     return TRUE;
764                 case CORPSE: /* fixed by polder@cs.vu.nl */
765                     if (touch_petrifies(&mons[obj->corpsenm])) {
766                         tmp = 1;
767                         hittxt = TRUE;
768                         You("hit %s with %s.", mon_nam(mon),
769                             corpse_xname(obj, (const char *) 0,
770                                          obj->dknown ? CXN_PFX_THE
771                                                      : CXN_ARTICLE));
772                         obj->dknown = 1;
773                         if (!munstone(mon, TRUE))
774                             minstapetrify(mon, TRUE);
775                         if (resists_ston(mon))
776                             break;
777                         /* note: hp may be <= 0 even if munstoned==TRUE */
778                         return (boolean) (mon->mhp > 0);
779 #if 0
780                     } else if (touch_petrifies(mdat)) {
781                         ; /* maybe turn the corpse into a statue? */
782 #endif
783                     }
784                     tmp = (obj->corpsenm >= LOW_PM ? mons[obj->corpsenm].msize
785                                                    : 0) + 1;
786                     break;
787
788 #define useup_eggs(o)                    \
789     {                                    \
790         if (thrown)                      \
791             obfree(o, (struct obj *) 0); \
792         else                             \
793             useupall(o);                 \
794         o = (struct obj *) 0;            \
795     } /* now gone */
796                 case EGG: {
797                     long cnt = obj->quan;
798
799                     tmp = 1; /* nominal physical damage */
800                     get_dmg_bonus = FALSE;
801                     hittxt = TRUE; /* message always given */
802                     /* egg is always either used up or transformed, so next
803                        hand-to-hand attack should yield a "bashing" mesg */
804                     if (obj == uwep)
805                         unweapon = TRUE;
806                     if (obj->spe && obj->corpsenm >= LOW_PM) {
807                         if (obj->quan < 5L)
808                             change_luck((schar) - (obj->quan));
809                         else
810                             change_luck(-5);
811                     }
812
813                     if (touch_petrifies(&mons[obj->corpsenm])) {
814                         /*learn_egg_type(obj->corpsenm);*/
815                         pline("Splat! You hit %s with %s %s egg%s!",
816                               mon_nam(mon),
817                               obj->known ? "the" : cnt > 1L ? "some" : "a",
818                               obj->known ? mons[obj->corpsenm].mname
819                                          : "petrifying",
820                               plur(cnt));
821                         obj->known = 1; /* (not much point...) */
822                         useup_eggs(obj);
823                         if (!munstone(mon, TRUE))
824                             minstapetrify(mon, TRUE);
825                         if (resists_ston(mon))
826                             break;
827                         return (boolean) (mon->mhp > 0);
828                     } else { /* ordinary egg(s) */
829                         const char *eggp =
830                             (obj->corpsenm != NON_PM && obj->known)
831                                 ? the(mons[obj->corpsenm].mname)
832                                 : (cnt > 1L) ? "some" : "an";
833                         You("hit %s with %s egg%s.", mon_nam(mon), eggp,
834                             plur(cnt));
835                         if (touch_petrifies(mdat) && !stale_egg(obj)) {
836                             pline_The("egg%s %s alive any more...", plur(cnt),
837                                       (cnt == 1L) ? "isn't" : "aren't");
838                             if (obj->timed)
839                                 obj_stop_timers(obj);
840                             obj->otyp = ROCK;
841                             obj->oclass = GEM_CLASS;
842                             obj->oartifact = 0;
843                             obj->spe = 0;
844                             obj->known = obj->dknown = obj->bknown = 0;
845                             obj->owt = weight(obj);
846                             if (thrown)
847                                 place_object(obj, mon->mx, mon->my);
848                         } else {
849                             pline("Splat!");
850                             useup_eggs(obj);
851                             exercise(A_WIS, FALSE);
852                         }
853                     }
854                     break;
855 #undef useup_eggs
856                 }
857                 case CLOVE_OF_GARLIC: /* no effect against demons */
858                     if (is_undead(mdat) || is_vampshifter(mon)) {
859                         monflee(mon, d(2, 4), FALSE, TRUE);
860                     }
861                     tmp = 1;
862                     break;
863                 case CREAM_PIE:
864                 case BLINDING_VENOM:
865                     mon->msleeping = 0;
866                     if (can_blnd(&youmonst, mon,
867                                  (uchar) (obj->otyp == BLINDING_VENOM
868                                              ? AT_SPIT
869                                              : AT_WEAP),
870                                  obj)) {
871                         if (Blind) {
872                             pline(obj->otyp == CREAM_PIE ? "Splat!"
873                                                          : "Splash!");
874                         } else if (obj->otyp == BLINDING_VENOM) {
875                             pline_The("venom blinds %s%s!", mon_nam(mon),
876                                       mon->mcansee ? "" : " further");
877                         } else {
878                             char *whom = mon_nam(mon);
879                             char *what = The(xname(obj));
880
881                             if (!thrown && obj->quan > 1L)
882                                 what = An(singular(obj, xname));
883                             /* note: s_suffix returns a modifiable buffer */
884                             if (haseyes(mdat)
885                                 && mdat != &mons[PM_FLOATING_EYE])
886                                 whom = strcat(strcat(s_suffix(whom), " "),
887                                               mbodypart(mon, FACE));
888                             pline("%s %s over %s!", what,
889                                   vtense(what, "splash"), whom);
890                         }
891                         setmangry(mon);
892                         mon->mcansee = 0;
893                         tmp = rn1(25, 21);
894                         if (((int) mon->mblinded + tmp) > 127)
895                             mon->mblinded = 127;
896                         else
897                             mon->mblinded += tmp;
898                     } else {
899                         pline(obj->otyp == CREAM_PIE ? "Splat!" : "Splash!");
900                         setmangry(mon);
901                     }
902                     if (thrown)
903                         obfree(obj, (struct obj *) 0);
904                     else
905                         useup(obj);
906                     hittxt = TRUE;
907                     get_dmg_bonus = FALSE;
908                     tmp = 0;
909                     break;
910                 case ACID_VENOM: /* thrown (or spit) */
911                     if (resists_acid(mon)) {
912                         Your("venom hits %s harmlessly.", mon_nam(mon));
913                         tmp = 0;
914                     } else {
915                         Your("venom burns %s!", mon_nam(mon));
916                         tmp = dmgval(obj, mon);
917                     }
918                     if (thrown)
919                         obfree(obj, (struct obj *) 0);
920                     else
921                         useup(obj);
922                     hittxt = TRUE;
923                     get_dmg_bonus = FALSE;
924                     break;
925                 default:
926                     /* non-weapons can damage because of their weight */
927                     /* (but not too much) */
928                     tmp = obj->owt / 100;
929                     if (is_wet_towel(obj)) {
930                         /* wielded wet towel should probably use whip skill
931                            (but not by setting objects[TOWEL].oc_skill==P_WHIP
932                            because that would turn towel into a weptool) */
933                         tmp += obj->spe;
934                         if (rn2(obj->spe + 1)) /* usually lose some wetness */
935                             dry_a_towel(obj, -1, TRUE);
936                     }
937                     if (tmp < 1)
938                         tmp = 1;
939                     else
940                         tmp = rnd(tmp);
941                     if (tmp > 6)
942                         tmp = 6;
943                     /*
944                      * Things like silver wands can arrive here so
945                      * so we need another silver check.
946                      */
947                     if (objects[obj->otyp].oc_material == SILVER
948                         && mon_hates_silver(mon)) {
949                         tmp += rnd(20);
950                         silvermsg = TRUE;
951                         silverobj = TRUE;
952                     }
953                 }
954             }
955         }
956     }
957
958     /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG)
959      *      *OR* if attacking bare-handed!! */
960
961     if (get_dmg_bonus && tmp > 0) {
962         tmp += u.udaminc;
963         /* If you throw using a propellor, you don't get a strength
964          * bonus but you do get an increase-damage bonus.
965          */
966         if (thrown != HMON_THROWN || !obj || !uwep
967             || !ammo_and_launcher(obj, uwep))
968             tmp += dbon();
969     }
970
971     if (valid_weapon_attack) {
972         struct obj *wep;
973
974         /* to be valid a projectile must have had the correct projector */
975         wep = PROJECTILE(obj) ? uwep : obj;
976         tmp += weapon_dam_bonus(wep);
977         /* [this assumes that `!thrown' implies wielded...] */
978         wtype = thrown ? weapon_type(wep) : uwep_skill_type();
979         use_skill(wtype, 1);
980     }
981
982     if (ispoisoned) {
983         int nopoison = (10 - (obj->owt / 10));
984
985         if (nopoison < 2)
986             nopoison = 2;
987         if (Role_if(PM_SAMURAI)) {
988             You("dishonorably use a poisoned weapon!");
989             adjalign(-sgn(u.ualign.type));
990         } else if (u.ualign.type == A_LAWFUL && u.ualign.record > -10) {
991             You_feel("like an evil coward for using a poisoned weapon.");
992             adjalign(-1);
993         }
994         if (obj && !rn2(nopoison)) {
995             /* remove poison now in case obj ends up in a bones file */
996             obj->opoisoned = FALSE;
997             /* defer "obj is no longer poisoned" until after hit message */
998             unpoisonmsg = TRUE;
999         }
1000         if (resists_poison(mon))
1001             needpoismsg = TRUE;
1002         else if (rn2(10))
1003             tmp += rnd(6);
1004         else
1005             poiskilled = TRUE;
1006     }
1007     if (tmp < 1) {
1008         /* make sure that negative damage adjustment can't result
1009            in inadvertently boosting the victim's hit points */
1010         tmp = 0;
1011         if (mdat == &mons[PM_SHADE]) {
1012             if (!hittxt) {
1013                 const char *what = *unconventional ? unconventional : "attack";
1014
1015                 Your("%s %s harmlessly through %s.", what,
1016                      vtense(what, "pass"), mon_nam(mon));
1017                 hittxt = TRUE;
1018             }
1019         } else {
1020             if (get_dmg_bonus)
1021                 tmp = 1;
1022         }
1023     }
1024
1025     if (jousting) {
1026         tmp += d(2, (obj == uwep) ? 10 : 2); /* [was in dmgval()] */
1027         You("joust %s%s", mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
1028         if (jousting < 0) {
1029             pline("%s shatters on impact!", Yname2(obj));
1030             /* (must be either primary or secondary weapon to get here) */
1031             u.twoweap = FALSE; /* untwoweapon() is too verbose here */
1032             if (obj == uwep)
1033                 uwepgone(); /* set unweapon */
1034             /* minor side-effect: broken lance won't split puddings */
1035             useup(obj);
1036             obj = 0;
1037         }
1038         /* avoid migrating a dead monster */
1039         if (mon->mhp > tmp) {
1040             mhurtle(mon, u.dx, u.dy, 1);
1041             mdat = mon->data; /* in case of a polymorph trap */
1042             if (DEADMONSTER(mon))
1043                 already_killed = TRUE;
1044         }
1045         hittxt = TRUE;
1046     } else if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) {
1047         /* VERY small chance of stunning opponent if unarmed. */
1048         if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) && !bigmonst(mdat)
1049             && !thick_skinned(mdat)) {
1050             if (canspotmon(mon))
1051                 pline("%s %s from your powerful strike!", Monnam(mon),
1052                       makeplural(stagger(mon->data, "stagger")));
1053             /* avoid migrating a dead monster */
1054             if (mon->mhp > tmp) {
1055                 mhurtle(mon, u.dx, u.dy, 1);
1056                 mdat = mon->data; /* in case of a polymorph trap */
1057                 if (DEADMONSTER(mon))
1058                     already_killed = TRUE;
1059             }
1060             hittxt = TRUE;
1061         }
1062     }
1063
1064     if (!already_killed)
1065         mon->mhp -= tmp;
1066     /* adjustments might have made tmp become less than what
1067        a level draining artifact has already done to max HP */
1068     if (mon->mhp > mon->mhpmax)
1069         mon->mhp = mon->mhpmax;
1070     if (mon->mhp < 1)
1071         destroyed = TRUE;
1072     if (mon->mtame && tmp > 0) {
1073         /* do this even if the pet is being killed (affects revival) */
1074         abuse_dog(mon); /* reduces tameness */
1075         /* flee if still alive and still tame; if already suffering from
1076            untimed fleeing, no effect, otherwise increases timed fleeing */
1077         if (mon->mtame && !destroyed)
1078             monflee(mon, 10 * rnd(tmp), FALSE, FALSE);
1079     }
1080     if ((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING])
1081         /* pudding is alive and healthy enough to split */
1082         && mon->mhp > 1 && !mon->mcan
1083         /* iron weapon using melee or polearm hit */
1084         && obj && obj == uwep && objects[obj->otyp].oc_material == IRON
1085         && hand_to_hand) {
1086         if (clone_mon(mon, 0, 0)) {
1087             pline("%s divides as you hit it!", Monnam(mon));
1088             hittxt = TRUE;
1089         }
1090     }
1091
1092     if (!hittxt /*( thrown => obj exists )*/
1093         && (!destroyed
1094             || (thrown && m_shot.n > 1 && m_shot.o == obj->otyp))) {
1095         if (thrown)
1096             hit(mshot_xname(obj), mon, exclam(tmp));
1097         else if (!flags.verbose)
1098             You("hit it.");
1099         else
1100             You("%s %s%s", Role_if(PM_BARBARIAN) ? "smite" : "hit",
1101                 mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
1102     }
1103
1104     if (silvermsg) {
1105         const char *fmt;
1106         char *whom = mon_nam(mon);
1107         char silverobjbuf[BUFSZ];
1108
1109         if (canspotmon(mon)) {
1110             if (barehand_silver_rings == 1)
1111                 fmt = "Your silver ring sears %s!";
1112             else if (barehand_silver_rings == 2)
1113                 fmt = "Your silver rings sear %s!";
1114             else if (silverobj && saved_oname[0]) {
1115                 Sprintf(silverobjbuf, "Your %s%s %s %%s!",
1116                         strstri(saved_oname, "silver") ? "" : "silver ",
1117                         saved_oname, vtense(saved_oname, "sear"));
1118                 fmt = silverobjbuf;
1119             } else
1120                 fmt = "The silver sears %s!";
1121         } else {
1122             *whom = highc(*whom); /* "it" -> "It" */
1123             fmt = "%s is seared!";
1124         }
1125         /* note: s_suffix returns a modifiable buffer */
1126         if (!noncorporeal(mdat) && !amorphous(mdat))
1127             whom = strcat(s_suffix(whom), " flesh");
1128         pline(fmt, whom);
1129     }
1130     /* if a "no longer poisoned" message is coming, it will be last;
1131        obj->opoisoned was cleared above and any message referring to
1132        "poisoned <obj>" has now been given; we want just "<obj>" for
1133        last message, so reformat while obj is still accessible */
1134     if (unpoisonmsg)
1135         Strcpy(saved_oname, cxname(obj));
1136
1137     /* [note: thrown obj might go away during killed/xkilled call] */
1138
1139     if (needpoismsg)
1140         pline_The("poison doesn't seem to affect %s.", mon_nam(mon));
1141     if (poiskilled) {
1142         pline_The("poison was deadly...");
1143         if (!already_killed)
1144             xkilled(mon, 0);
1145         destroyed = TRUE; /* return FALSE; */
1146     } else if (destroyed) {
1147         if (!already_killed)
1148             killed(mon); /* takes care of most messages */
1149     } else if (u.umconf && hand_to_hand) {
1150         nohandglow(mon);
1151         if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) {
1152             mon->mconf = 1;
1153             if (!mon->mstun && mon->mcanmove && !mon->msleeping
1154                 && canseemon(mon))
1155                 pline("%s appears confused.", Monnam(mon));
1156         }
1157     }
1158     if (unpoisonmsg)
1159         Your("%s %s no longer poisoned.", saved_oname,
1160              vtense(saved_oname, "are"));
1161
1162     return destroyed ? FALSE : TRUE;
1163 }
1164
1165 STATIC_OVL boolean
1166 shade_aware(obj)
1167 struct obj *obj;
1168 {
1169     if (!obj)
1170         return FALSE;
1171     /*
1172      * The things in this list either
1173      * 1) affect shades.
1174      *  OR
1175      * 2) are dealt with properly by other routines
1176      *    when it comes to shades.
1177      */
1178     if (obj->otyp == BOULDER
1179         || obj->otyp == HEAVY_IRON_BALL
1180         || obj->otyp == IRON_CHAIN      /* dmgval handles those first three */
1181         || obj->otyp == MIRROR          /* silver in the reflective surface */
1182         || obj->otyp == CLOVE_OF_GARLIC /* causes shades to flee */
1183         || objects[obj->otyp].oc_material == SILVER)
1184         return TRUE;
1185     return FALSE;
1186 }
1187
1188 /* check whether slippery clothing protects from hug or wrap attack */
1189 /* [currently assumes that you are the attacker] */
1190 STATIC_OVL boolean
1191 m_slips_free(mdef, mattk)
1192 struct monst *mdef;
1193 struct attack *mattk;
1194 {
1195     struct obj *obj;
1196
1197     if (mattk->adtyp == AD_DRIN) {
1198         /* intelligence drain attacks the head */
1199         obj = which_armor(mdef, W_ARMH);
1200     } else {
1201         /* grabbing attacks the body */
1202         obj = which_armor(mdef, W_ARMC); /* cloak */
1203         if (!obj)
1204             obj = which_armor(mdef, W_ARM); /* suit */
1205         if (!obj)
1206             obj = which_armor(mdef, W_ARMU); /* shirt */
1207     }
1208
1209     /* if monster's cloak/armor is greased, your grab slips off; this
1210        protection might fail (33% chance) when the armor is cursed */
1211     if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK)
1212         && (!obj->cursed || rn2(3))) {
1213         You("%s %s %s %s!",
1214             mattk->adtyp == AD_WRAP ? "slip off of"
1215                                     : "grab, but cannot hold onto",
1216             s_suffix(mon_nam(mdef)), obj->greased ? "greased" : "slippery",
1217             /* avoid "slippery slippery cloak"
1218                for undiscovered oilskin cloak */
1219             (obj->greased || objects[obj->otyp].oc_name_known)
1220                 ? xname(obj)
1221                 : cloak_simple_name(obj));
1222
1223         if (obj->greased && !rn2(2)) {
1224             pline_The("grease wears off.");
1225             obj->greased = 0;
1226         }
1227         return TRUE;
1228     }
1229     return FALSE;
1230 }
1231
1232 /* used when hitting a monster with a lance while mounted;
1233    1: joust hit; 0: ordinary hit; -1: joust but break lance */
1234 STATIC_OVL int
1235 joust(mon, obj)
1236 struct monst *mon; /* target */
1237 struct obj *obj;   /* weapon */
1238 {
1239     int skill_rating, joust_dieroll;
1240
1241     if (Fumbling || Stunned)
1242         return 0;
1243     /* sanity check; lance must be wielded in order to joust */
1244     if (obj != uwep && (obj != uswapwep || !u.twoweap))
1245         return 0;
1246
1247     /* if using two weapons, use worse of lance and two-weapon skills */
1248     skill_rating = P_SKILL(weapon_type(obj)); /* lance skill */
1249     if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating)
1250         skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT);
1251     if (skill_rating == P_ISRESTRICTED)
1252         skill_rating = P_UNSKILLED; /* 0=>1 */
1253
1254     /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */
1255     if ((joust_dieroll = rn2(5)) < skill_rating) {
1256         if (joust_dieroll == 0 && rnl(50) == (50 - 1) && !unsolid(mon->data)
1257             && !obj_resists(obj, 0, 100))
1258             return -1; /* hit that breaks lance */
1259         return 1;      /* successful joust */
1260     }
1261     return 0; /* no joust bonus; revert to ordinary attack */
1262 }
1263
1264 /*
1265  * Send in a demon pet for the hero.  Exercise wisdom.
1266  *
1267  * This function used to be inline to damageum(), but the Metrowerks compiler
1268  * (DR4 and DR4.5) screws up with an internal error 5 "Expression Too
1269  * Complex."
1270  * Pulling it out makes it work.
1271  */
1272 STATIC_OVL void
1273 demonpet()
1274 {
1275     int i;
1276     struct permonst *pm;
1277     struct monst *dtmp;
1278
1279     pline("Some hell-p has arrived!");
1280     i = !rn2(6) ? ndemon(u.ualign.type) : NON_PM;
1281     pm = i != NON_PM ? &mons[i] : youmonst.data;
1282     if ((dtmp = makemon(pm, u.ux, u.uy, NO_MM_FLAGS)) != 0)
1283         (void) tamedog(dtmp, (struct obj *) 0);
1284     exercise(A_WIS, TRUE);
1285 }
1286
1287 STATIC_OVL boolean
1288 theft_petrifies(otmp)
1289 struct obj *otmp;
1290 {
1291     if (uarmg || otmp->otyp != CORPSE
1292         || !touch_petrifies(&mons[otmp->corpsenm]) || Stone_resistance)
1293         return FALSE;
1294
1295 #if 0   /* no poly_when_stoned() critter has theft capability */
1296     if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) {
1297         display_nhwindow(WIN_MESSAGE, FALSE);   /* --More-- */
1298         return TRUE;
1299     }
1300 #endif
1301
1302     /* stealing this corpse is fatal... */
1303     instapetrify(corpse_xname(otmp, "stolen", CXN_ARTICLE));
1304     /* apparently wasn't fatal after all... */
1305     return TRUE;
1306 }
1307
1308 /*
1309  * Player uses theft attack against monster.
1310  *
1311  * If the target is wearing body armor, take all of its possessions;
1312  * otherwise, take one object.  [Is this really the behavior we want?]
1313  */
1314 STATIC_OVL void
1315 steal_it(mdef, mattk)
1316 struct monst *mdef;
1317 struct attack *mattk;
1318 {
1319     struct obj *otmp, *stealoid, **minvent_ptr;
1320     long unwornmask;
1321
1322     if (!mdef->minvent)
1323         return; /* nothing to take */
1324
1325     /* look for worn body armor */
1326     stealoid = (struct obj *) 0;
1327     if (could_seduce(&youmonst, mdef, mattk)) {
1328         /* find armor, and move it to end of inventory in the process */
1329         minvent_ptr = &mdef->minvent;
1330         while ((otmp = *minvent_ptr) != 0)
1331             if (otmp->owornmask & W_ARM) {
1332                 if (stealoid)
1333                     panic("steal_it: multiple worn suits");
1334                 *minvent_ptr = otmp->nobj; /* take armor out of minvent */
1335                 stealoid = otmp;
1336                 stealoid->nobj = (struct obj *) 0;
1337             } else {
1338                 minvent_ptr = &otmp->nobj;
1339             }
1340         *minvent_ptr = stealoid; /* put armor back into minvent */
1341     }
1342
1343     if (stealoid) { /* we will be taking everything */
1344         if (gender(mdef) == (int) u.mfemale && youmonst.data->mlet == S_NYMPH)
1345             You("charm %s.  She gladly hands over her possessions.",
1346                 mon_nam(mdef));
1347         else
1348             You("seduce %s and %s starts to take off %s clothes.",
1349                 mon_nam(mdef), mhe(mdef), mhis(mdef));
1350     }
1351
1352     while ((otmp = mdef->minvent) != 0) {
1353         if (!Upolyd)
1354             break; /* no longer have ability to steal */
1355         /* take the object away from the monster */
1356         obj_extract_self(otmp);
1357         if ((unwornmask = otmp->owornmask) != 0L) {
1358             mdef->misc_worn_check &= ~unwornmask;
1359             if (otmp->owornmask & W_WEP)
1360                 setmnotwielded(mdef, otmp);
1361             otmp->owornmask = 0L;
1362             update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
1363
1364             if (otmp == stealoid) /* special message for final item */
1365                 pline("%s finishes taking off %s suit.", Monnam(mdef),
1366                       mhis(mdef));
1367         }
1368         /* give the object to the character */
1369         otmp = hold_another_object(otmp, "You snatched but dropped %s.",
1370                                    doname(otmp), "You steal: ");
1371         if (otmp->where != OBJ_INVENT)
1372             continue;
1373         if (theft_petrifies(otmp))
1374             break; /* stop thieving even though hero survived */
1375         /* more take-away handling, after theft message */
1376         if (unwornmask & W_WEP) { /* stole wielded weapon */
1377             possibly_unwield(mdef, FALSE);
1378         } else if (unwornmask & W_ARMG) { /* stole worn gloves */
1379             mselftouch(mdef, (const char *) 0, TRUE);
1380             if (mdef->mhp <= 0) /* it's now a statue */
1381                 return;         /* can't continue stealing */
1382         }
1383
1384         if (!stealoid)
1385             break; /* only taking one item */
1386     }
1387 }
1388
1389 int
1390 damageum(mdef, mattk)
1391 register struct monst *mdef;
1392 register struct attack *mattk;
1393 {
1394     register struct permonst *pd = mdef->data;
1395     int armpro, tmp = d((int) mattk->damn, (int) mattk->damd);
1396     boolean negated;
1397
1398     armpro = magic_negation(mdef);
1399     /* since hero can't be cancelled, only defender's armor applies */
1400     negated = !(rn2(10) >= 3 * armpro);
1401
1402     if (is_demon(youmonst.data) && !rn2(13) && !uwep
1403         && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS
1404         && u.umonnum != PM_BALROG) {
1405         demonpet();
1406         return 0;
1407     }
1408     switch (mattk->adtyp) {
1409     case AD_STUN:
1410         if (!Blind)
1411             pline("%s %s for a moment.", Monnam(mdef),
1412                   makeplural(stagger(pd, "stagger")));
1413         mdef->mstun = 1;
1414         goto physical;
1415     case AD_LEGS:
1416 #if 0
1417         if (u.ucancelled) {
1418             tmp = 0;
1419             break;
1420         }
1421 #endif
1422         goto physical;
1423     case AD_WERE: /* no special effect on monsters */
1424     case AD_HEAL: /* likewise */
1425     case AD_PHYS:
1426     physical:
1427         if (mattk->aatyp == AT_WEAP) {
1428             if (uwep)
1429                 tmp = 0;
1430         } else if (mattk->aatyp == AT_KICK) {
1431             if (thick_skinned(pd))
1432                 tmp = 0;
1433             if (pd == &mons[PM_SHADE]) {
1434                 if (!(uarmf && uarmf->blessed)) {
1435                     impossible("bad shade attack function flow?");
1436                     tmp = 0;
1437                 } else
1438                     tmp = rnd(4); /* bless damage */
1439             }
1440             /* add ring(s) of increase damage */
1441             if (u.udaminc > 0) {
1442                 /* applies even if damage was 0 */
1443                 tmp += u.udaminc;
1444             } else if (tmp > 0) {
1445                 /* ring(s) might be negative; avoid converting
1446                    0 to non-0 or positive to non-positive */
1447                 tmp += u.udaminc;
1448                 if (tmp < 1)
1449                     tmp = 1;
1450             }
1451         }
1452         break;
1453     case AD_FIRE:
1454         if (negated) {
1455             tmp = 0;
1456             break;
1457         }
1458         if (!Blind)
1459             pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk));
1460         if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) {
1461             if (!Blind)
1462                 pline("%s burns completely!", Monnam(mdef));
1463             xkilled(mdef, 2);
1464             tmp = 0;
1465             break;
1466             /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1467         }
1468         tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
1469         tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
1470         if (resists_fire(mdef)) {
1471             if (!Blind)
1472                 pline_The("fire doesn't heat %s!", mon_nam(mdef));
1473             golemeffects(mdef, AD_FIRE, tmp);
1474             shieldeff(mdef->mx, mdef->my);
1475             tmp = 0;
1476         }
1477         /* only potions damage resistant players in destroy_item */
1478         tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
1479         break;
1480     case AD_COLD:
1481         if (negated) {
1482             tmp = 0;
1483             break;
1484         }
1485         if (!Blind)
1486             pline("%s is covered in frost!", Monnam(mdef));
1487         if (resists_cold(mdef)) {
1488             shieldeff(mdef->mx, mdef->my);
1489             if (!Blind)
1490                 pline_The("frost doesn't chill %s!", mon_nam(mdef));
1491             golemeffects(mdef, AD_COLD, tmp);
1492             tmp = 0;
1493         }
1494         tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
1495         break;
1496     case AD_ELEC:
1497         if (negated) {
1498             tmp = 0;
1499             break;
1500         }
1501         if (!Blind)
1502             pline("%s is zapped!", Monnam(mdef));
1503         tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
1504         if (resists_elec(mdef)) {
1505             if (!Blind)
1506                 pline_The("zap doesn't shock %s!", mon_nam(mdef));
1507             golemeffects(mdef, AD_ELEC, tmp);
1508             shieldeff(mdef->mx, mdef->my);
1509             tmp = 0;
1510         }
1511         /* only rings damage resistant players in destroy_item */
1512         tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
1513         break;
1514     case AD_ACID:
1515         if (resists_acid(mdef))
1516             tmp = 0;
1517         break;
1518     case AD_STON:
1519         if (!munstone(mdef, TRUE))
1520             minstapetrify(mdef, TRUE);
1521         tmp = 0;
1522         break;
1523     case AD_SSEX:
1524     case AD_SEDU:
1525     case AD_SITM:
1526         steal_it(mdef, mattk);
1527         tmp = 0;
1528         break;
1529     case AD_SGLD:
1530         /* This you as a leprechaun, so steal
1531            real gold only, no lesser coins */
1532         {
1533             struct obj *mongold = findgold(mdef->minvent);
1534             if (mongold) {
1535                 obj_extract_self(mongold);
1536                 if (merge_choice(invent, mongold) || inv_cnt(FALSE) < 52) {
1537                     addinv(mongold);
1538                     Your("purse feels heavier.");
1539                 } else {
1540                     You("grab %s's gold, but find no room in your knapsack.",
1541                         mon_nam(mdef));
1542                     dropy(mongold);
1543                 }
1544             }
1545         }
1546         exercise(A_DEX, TRUE);
1547         tmp = 0;
1548         break;
1549     case AD_TLPT:
1550         if (tmp <= 0)
1551             tmp = 1;
1552         if (!negated && tmp < mdef->mhp) {
1553             char nambuf[BUFSZ];
1554             boolean u_saw_mon =
1555                 canseemon(mdef) || (u.uswallow && u.ustuck == mdef);
1556             /* record the name before losing sight of monster */
1557             Strcpy(nambuf, Monnam(mdef));
1558             if (u_teleport_mon(mdef, FALSE) && u_saw_mon
1559                 && !(canseemon(mdef) || (u.uswallow && u.ustuck == mdef)))
1560                 pline("%s suddenly disappears!", nambuf);
1561         }
1562         break;
1563     case AD_BLND:
1564         if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj *) 0)) {
1565             if (!Blind && mdef->mcansee)
1566                 pline("%s is blinded.", Monnam(mdef));
1567             mdef->mcansee = 0;
1568             tmp += mdef->mblinded;
1569             if (tmp > 127)
1570                 tmp = 127;
1571             mdef->mblinded = tmp;
1572         }
1573         tmp = 0;
1574         break;
1575     case AD_CURS:
1576         if (night() && !rn2(10) && !mdef->mcan) {
1577             if (pd == &mons[PM_CLAY_GOLEM]) {
1578                 if (!Blind)
1579                     pline("Some writing vanishes from %s head!",
1580                           s_suffix(mon_nam(mdef)));
1581                 xkilled(mdef, 0);
1582                 /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1583             } else {
1584                 mdef->mcan = 1;
1585                 You("chuckle.");
1586             }
1587         }
1588         tmp = 0;
1589         break;
1590     case AD_DRLI:
1591         if (!negated && !rn2(3) && !resists_drli(mdef)) {
1592             int xtmp = d(2, 6);
1593             pline("%s suddenly seems weaker!", Monnam(mdef));
1594             mdef->mhpmax -= xtmp;
1595             if ((mdef->mhp -= xtmp) <= 0 || !mdef->m_lev) {
1596                 pline("%s dies!", Monnam(mdef));
1597                 xkilled(mdef, 0);
1598             } else
1599                 mdef->m_lev--;
1600             tmp = 0;
1601         }
1602         break;
1603     case AD_RUST:
1604         if (pd == &mons[PM_IRON_GOLEM]) {
1605             pline("%s falls to pieces!", Monnam(mdef));
1606             xkilled(mdef, 0);
1607         }
1608         erode_armor(mdef, ERODE_RUST);
1609         tmp = 0;
1610         break;
1611     case AD_CORR:
1612         erode_armor(mdef, ERODE_CORRODE);
1613         tmp = 0;
1614         break;
1615     case AD_DCAY:
1616         if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) {
1617             pline("%s falls to pieces!", Monnam(mdef));
1618             xkilled(mdef, 0);
1619         }
1620         erode_armor(mdef, ERODE_ROT);
1621         tmp = 0;
1622         break;
1623     case AD_DREN:
1624         if (!negated && !rn2(4))
1625             xdrainenergym(mdef, TRUE);
1626         tmp = 0;
1627         break;
1628     case AD_DRST:
1629     case AD_DRDX:
1630     case AD_DRCO:
1631         if (!negated && !rn2(8)) {
1632             Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk));
1633             if (resists_poison(mdef))
1634                 pline_The("poison doesn't seem to affect %s.", mon_nam(mdef));
1635             else {
1636                 if (!rn2(10)) {
1637                     Your("poison was deadly...");
1638                     tmp = mdef->mhp;
1639                 } else
1640                     tmp += rn1(10, 6);
1641             }
1642         }
1643         break;
1644     case AD_DRIN: {
1645         struct obj *helmet;
1646
1647         if (notonhead || !has_head(pd)) {
1648             pline("%s doesn't seem harmed.", Monnam(mdef));
1649             tmp = 0;
1650             if (!Unchanging && pd == &mons[PM_GREEN_SLIME]) {
1651                 if (!Slimed) {
1652                     You("suck in some slime and don't feel very well.");
1653                     make_slimed(10L, (char *) 0);
1654                 }
1655             }
1656             break;
1657         }
1658         if (m_slips_free(mdef, mattk))
1659             break;
1660
1661         if ((helmet = which_armor(mdef, W_ARMH)) != 0 && rn2(8)) {
1662             pline("%s %s blocks your attack to %s head.",
1663                   s_suffix(Monnam(mdef)), helm_simple_name(helmet),
1664                   mhis(mdef));
1665             break;
1666         }
1667
1668         (void) eat_brains(&youmonst, mdef, TRUE, &tmp);
1669         break;
1670     }
1671     case AD_STCK:
1672         if (!negated && !sticks(pd))
1673             u.ustuck = mdef; /* it's now stuck to you */
1674         break;
1675     case AD_WRAP:
1676         if (!sticks(pd)) {
1677             if (!u.ustuck && !rn2(10)) {
1678                 if (m_slips_free(mdef, mattk)) {
1679                     tmp = 0;
1680                 } else {
1681                     You("swing yourself around %s!", mon_nam(mdef));
1682                     u.ustuck = mdef;
1683                 }
1684             } else if (u.ustuck == mdef) {
1685                 /* Monsters don't wear amulets of magical breathing */
1686                 if (is_pool(u.ux, u.uy) && !is_swimmer(pd)
1687                     && !amphibious(pd)) {
1688                     You("drown %s...", mon_nam(mdef));
1689                     tmp = mdef->mhp;
1690                 } else if (mattk->aatyp == AT_HUGS)
1691                     pline("%s is being crushed.", Monnam(mdef));
1692             } else {
1693                 tmp = 0;
1694                 if (flags.verbose)
1695                     You("brush against %s %s.", s_suffix(mon_nam(mdef)),
1696                         mbodypart(mdef, LEG));
1697             }
1698         } else
1699             tmp = 0;
1700         break;
1701     case AD_PLYS:
1702         if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
1703             if (!Blind)
1704                 pline("%s is frozen by you!", Monnam(mdef));
1705             paralyze_monst(mdef, rnd(10));
1706         }
1707         break;
1708     case AD_SLEE:
1709         if (!negated && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) {
1710             if (!Blind)
1711                 pline("%s is put to sleep by you!", Monnam(mdef));
1712             slept_monst(mdef);
1713         }
1714         break;
1715     case AD_SLIM:
1716         if (negated)
1717             break; /* physical damage only */
1718         if (!rn2(4) && !slimeproof(pd)) {
1719             if (!munslime(mdef, TRUE) && mdef->mhp > 0) {
1720                 /* this assumes newcham() won't fail; since hero has
1721                    a slime attack, green slimes haven't been geno'd */
1722                 You("turn %s into slime.", mon_nam(mdef));
1723                 if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE))
1724                     pd = mdef->data;
1725             }
1726             /* munslime attempt could have been fatal */
1727             if (mdef->mhp < 1)
1728                 return 2; /* skip death message */
1729             tmp = 0;
1730         }
1731         break;
1732     case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1733         /* there's no msomearmor() function, so just do damage */
1734         /* if (negated) break; */
1735         break;
1736     case AD_SLOW:
1737         if (!negated && mdef->mspeed != MSLOW) {
1738             unsigned int oldspeed = mdef->mspeed;
1739
1740             mon_adjust_speed(mdef, -1, (struct obj *) 0);
1741             if (mdef->mspeed != oldspeed && canseemon(mdef))
1742                 pline("%s slows down.", Monnam(mdef));
1743         }
1744         break;
1745     case AD_CONF:
1746         if (!mdef->mconf) {
1747             if (canseemon(mdef))
1748                 pline("%s looks confused.", Monnam(mdef));
1749             mdef->mconf = 1;
1750         }
1751         break;
1752     default:
1753         tmp = 0;
1754         break;
1755     }
1756
1757     mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */
1758     if ((mdef->mhp -= tmp) < 1) {
1759         if (mdef->mtame && !cansee(mdef->mx, mdef->my)) {
1760             You_feel("embarrassed for a moment.");
1761             if (tmp)
1762                 xkilled(mdef, 0); /* !tmp but hp<1: already killed */
1763         } else if (!flags.verbose) {
1764             You("destroy it!");
1765             if (tmp)
1766                 xkilled(mdef, 0);
1767         } else if (tmp)
1768             killed(mdef);
1769         return 2;
1770     }
1771     return 1;
1772 }
1773
1774 STATIC_OVL int
1775 explum(mdef, mattk)
1776 register struct monst *mdef;
1777 register struct attack *mattk;
1778 {
1779     register int tmp = d((int) mattk->damn, (int) mattk->damd);
1780
1781     You("explode!");
1782     switch (mattk->adtyp) {
1783         boolean resistance; /* only for cold/fire/elec */
1784
1785     case AD_BLND:
1786         if (!resists_blnd(mdef)) {
1787             pline("%s is blinded by your flash of light!", Monnam(mdef));
1788             mdef->mblinded = min((int) mdef->mblinded + tmp, 127);
1789             mdef->mcansee = 0;
1790         }
1791         break;
1792     case AD_HALU:
1793         if (haseyes(mdef->data) && mdef->mcansee) {
1794             pline("%s is affected by your flash of light!", Monnam(mdef));
1795             mdef->mconf = 1;
1796         }
1797         break;
1798     case AD_COLD:
1799         resistance = resists_cold(mdef);
1800         goto common;
1801     case AD_FIRE:
1802         resistance = resists_fire(mdef);
1803         goto common;
1804     case AD_ELEC:
1805         resistance = resists_elec(mdef);
1806     common:
1807         if (!resistance) {
1808             pline("%s gets blasted!", Monnam(mdef));
1809             mdef->mhp -= tmp;
1810             if (mdef->mhp <= 0) {
1811                 killed(mdef);
1812                 return 2;
1813             }
1814         } else {
1815             shieldeff(mdef->mx, mdef->my);
1816             if (is_golem(mdef->data))
1817                 golemeffects(mdef, (int) mattk->adtyp, tmp);
1818             else
1819                 pline_The("blast doesn't seem to affect %s.", mon_nam(mdef));
1820         }
1821         break;
1822     default:
1823         break;
1824     }
1825     return 1;
1826 }
1827
1828 STATIC_OVL void
1829 start_engulf(mdef)
1830 struct monst *mdef;
1831 {
1832     if (!Invisible) {
1833         map_location(u.ux, u.uy, TRUE);
1834         tmp_at(DISP_ALWAYS, mon_to_glyph(&youmonst));
1835         tmp_at(mdef->mx, mdef->my);
1836     }
1837     You("engulf %s!", mon_nam(mdef));
1838     delay_output();
1839     delay_output();
1840 }
1841
1842 STATIC_OVL void
1843 end_engulf()
1844 {
1845     if (!Invisible) {
1846         tmp_at(DISP_END, 0);
1847         newsym(u.ux, u.uy);
1848     }
1849 }
1850
1851 STATIC_OVL int
1852 gulpum(mdef, mattk)
1853 register struct monst *mdef;
1854 register struct attack *mattk;
1855 {
1856 #ifdef LINT /* static char msgbuf[BUFSZ]; */
1857     char msgbuf[BUFSZ];
1858 #else
1859     static char msgbuf[BUFSZ]; /* for nomovemsg */
1860 #endif
1861     register int tmp;
1862     register int dam = d((int) mattk->damn, (int) mattk->damd);
1863     boolean fatal_gulp;
1864     struct obj *otmp;
1865     struct permonst *pd = mdef->data;
1866
1867     /* Not totally the same as for real monsters.  Specifically, these
1868      * don't take multiple moves.  (It's just too hard, for too little
1869      * result, to program monsters which attack from inside you, which
1870      * would be necessary if done accurately.)  Instead, we arbitrarily
1871      * kill the monster immediately for AD_DGST and we regurgitate them
1872      * after exactly 1 round of attack otherwise.  -KAA
1873      */
1874
1875     if (!engulf_target(&youmonst, mdef))
1876         return 0;
1877
1878     if (u.uhunger < 1500 && !u.uswallow) {
1879         for (otmp = mdef->minvent; otmp; otmp = otmp->nobj)
1880             (void) snuff_lit(otmp);
1881
1882         /* engulfing a cockatrice or digesting a Rider or Medusa */
1883         fatal_gulp = (touch_petrifies(pd) && !Stone_resistance)
1884                      || (mattk->adtyp == AD_DGST
1885                          && (is_rider(pd) || (pd == &mons[PM_MEDUSA]
1886                                               && !Stone_resistance)));
1887
1888         if ((mattk->adtyp == AD_DGST && !Slow_digestion) || fatal_gulp)
1889             eating_conducts(pd);
1890
1891         if (fatal_gulp && !is_rider(pd)) { /* petrification */
1892             char kbuf[BUFSZ];
1893             const char *mname = pd->mname;
1894
1895             if (!type_is_pname(pd))
1896                 mname = an(mname);
1897             You("englut %s.", mon_nam(mdef));
1898             Sprintf(kbuf, "swallowing %s whole", mname);
1899             instapetrify(kbuf);
1900         } else {
1901             start_engulf(mdef);
1902             switch (mattk->adtyp) {
1903             case AD_DGST:
1904                 /* eating a Rider or its corpse is fatal */
1905                 if (is_rider(pd)) {
1906                     pline("Unfortunately, digesting any of it is fatal.");
1907                     end_engulf();
1908                     Sprintf(killer.name, "unwisely tried to eat %s",
1909                             pd->mname);
1910                     killer.format = NO_KILLER_PREFIX;
1911                     done(DIED);
1912                     return 0; /* lifesaved */
1913                 }
1914
1915                 if (Slow_digestion) {
1916                     dam = 0;
1917                     break;
1918                 }
1919
1920                 /* Use up amulet of life saving */
1921                 if (!!(otmp = mlifesaver(mdef)))
1922                     m_useup(mdef, otmp);
1923
1924                 newuhs(FALSE);
1925                 xkilled(mdef, 2);
1926                 if (mdef->mhp > 0) { /* monster lifesaved */
1927                     You("hurriedly regurgitate the sizzling in your %s.",
1928                         body_part(STOMACH));
1929                 } else {
1930                     tmp = 1 + (pd->cwt >> 8);
1931                     if (corpse_chance(mdef, &youmonst, TRUE)
1932                         && !(mvitals[monsndx(pd)].mvflags & G_NOCORPSE)) {
1933                         /* nutrition only if there can be a corpse */
1934                         u.uhunger += (pd->cnutrit + 1) / 2;
1935                     } else
1936                         tmp = 0;
1937                     Sprintf(msgbuf, "You totally digest %s.", mon_nam(mdef));
1938                     if (tmp != 0) {
1939                         /* setting afternmv = end_engulf is tempting,
1940                          * but will cause problems if the player is
1941                          * attacked (which uses his real location) or
1942                          * if his See_invisible wears off
1943                          */
1944                         You("digest %s.", mon_nam(mdef));
1945                         if (Slow_digestion)
1946                             tmp *= 2;
1947                         nomul(-tmp);
1948                         multi_reason = "digesting something";
1949                         nomovemsg = msgbuf;
1950                     } else
1951                         pline1(msgbuf);
1952                     if (pd == &mons[PM_GREEN_SLIME]) {
1953                         Sprintf(msgbuf, "%s isn't sitting well with you.",
1954                                 The(pd->mname));
1955                         if (!Unchanging) {
1956                             make_slimed(5L, (char *) 0);
1957                         }
1958                     } else
1959                         exercise(A_CON, TRUE);
1960                 }
1961                 end_engulf();
1962                 return 2;
1963             case AD_PHYS:
1964                 if (youmonst.data == &mons[PM_FOG_CLOUD]) {
1965                     pline("%s is laden with your moisture.", Monnam(mdef));
1966                     if (amphibious(pd) && !flaming(pd)) {
1967                         dam = 0;
1968                         pline("%s seems unharmed.", Monnam(mdef));
1969                     }
1970                 } else
1971                     pline("%s is pummeled with your debris!", Monnam(mdef));
1972                 break;
1973             case AD_ACID:
1974                 pline("%s is covered with your goo!", Monnam(mdef));
1975                 if (resists_acid(mdef)) {
1976                     pline("It seems harmless to %s.", mon_nam(mdef));
1977                     dam = 0;
1978                 }
1979                 break;
1980             case AD_BLND:
1981                 if (can_blnd(&youmonst, mdef, mattk->aatyp,
1982                              (struct obj *) 0)) {
1983                     if (mdef->mcansee)
1984                         pline("%s can't see in there!", Monnam(mdef));
1985                     mdef->mcansee = 0;
1986                     dam += mdef->mblinded;
1987                     if (dam > 127)
1988                         dam = 127;
1989                     mdef->mblinded = dam;
1990                 }
1991                 dam = 0;
1992                 break;
1993             case AD_ELEC:
1994                 if (rn2(2)) {
1995                     pline_The("air around %s crackles with electricity.",
1996                               mon_nam(mdef));
1997                     if (resists_elec(mdef)) {
1998                         pline("%s seems unhurt.", Monnam(mdef));
1999                         dam = 0;
2000                     }
2001                     golemeffects(mdef, (int) mattk->adtyp, dam);
2002                 } else
2003                     dam = 0;
2004                 break;
2005             case AD_COLD:
2006                 if (rn2(2)) {
2007                     if (resists_cold(mdef)) {
2008                         pline("%s seems mildly chilly.", Monnam(mdef));
2009                         dam = 0;
2010                     } else
2011                         pline("%s is freezing to death!", Monnam(mdef));
2012                     golemeffects(mdef, (int) mattk->adtyp, dam);
2013                 } else
2014                     dam = 0;
2015                 break;
2016             case AD_FIRE:
2017                 if (rn2(2)) {
2018                     if (resists_fire(mdef)) {
2019                         pline("%s seems mildly hot.", Monnam(mdef));
2020                         dam = 0;
2021                     } else
2022                         pline("%s is burning to a crisp!", Monnam(mdef));
2023                     golemeffects(mdef, (int) mattk->adtyp, dam);
2024                 } else
2025                     dam = 0;
2026                 break;
2027             case AD_DREN:
2028                 if (!rn2(4))
2029                     xdrainenergym(mdef, TRUE);
2030                 dam = 0;
2031                 break;
2032             }
2033             end_engulf();
2034             if ((mdef->mhp -= dam) <= 0) {
2035                 killed(mdef);
2036                 if (mdef->mhp <= 0) /* not lifesaved */
2037                     return 2;
2038             }
2039             You("%s %s!", is_animal(youmonst.data) ? "regurgitate" : "expel",
2040                 mon_nam(mdef));
2041             if (Slow_digestion || is_animal(youmonst.data)) {
2042                 pline("Obviously, you didn't like %s taste.",
2043                       s_suffix(mon_nam(mdef)));
2044             }
2045         }
2046     }
2047     return 0;
2048 }
2049
2050 void
2051 missum(mdef, mattk, wouldhavehit)
2052 register struct monst *mdef;
2053 register struct attack *mattk;
2054 boolean wouldhavehit;
2055 {
2056     if (wouldhavehit) /* monk is missing due to penalty for wearing suit */
2057         Your("armor is rather cumbersome...");
2058
2059     if (could_seduce(&youmonst, mdef, mattk))
2060         You("pretend to be friendly to %s.", mon_nam(mdef));
2061     else if (canspotmon(mdef) && flags.verbose)
2062         You("miss %s.", mon_nam(mdef));
2063     else
2064         You("miss it.");
2065     if (!mdef->msleeping && mdef->mcanmove)
2066         wakeup(mdef);
2067 }
2068
2069 /* attack monster as a monster. */
2070 STATIC_OVL boolean
2071 hmonas(mon)
2072 register struct monst *mon;
2073 {
2074     struct attack *mattk, alt_attk;
2075     struct obj *weapon;
2076     boolean altwep = FALSE, weapon_used = FALSE;
2077     int i, tmp, armorpenalty, sum[NATTK], nsum = 0, dhit = 0, attknum = 0;
2078
2079     for (i = 0; i < NATTK; i++) {
2080         sum[i] = 0;
2081         mattk = getmattk(youmonst.data, i, sum, &alt_attk);
2082         switch (mattk->aatyp) {
2083         case AT_WEAP:
2084         use_weapon:
2085             /* Certain monsters don't use weapons when encountered as enemies,
2086              * but players who polymorph into them have hands or claws and
2087              * thus should be able to use weapons.  This shouldn't prohibit
2088              * the use of most special abilities, either.
2089              * If monster has multiple claw attacks, only one can use weapon.
2090              */
2091             weapon_used = TRUE;
2092             /* Potential problem: if the monster gets multiple weapon attacks,
2093              * we currently allow the player to get each of these as a weapon
2094              * attack.  Is this really desirable?
2095              */
2096             /* approximate two-weapon mode */
2097             weapon = (altwep && uswapwep) ? uswapwep : uwep;
2098             altwep = !altwep; /* toggle for next attack */
2099             tmp = find_roll_to_hit(mon, AT_WEAP, weapon, &attknum,
2100                                    &armorpenalty);
2101             dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
2102             /* Enemy dead, before any special abilities used */
2103             if (!known_hitum(mon, weapon, &dhit, tmp, armorpenalty, mattk)) {
2104                 sum[i] = 2;
2105                 break;
2106             } else
2107                 sum[i] = dhit;
2108             /* might be a worm that gets cut in half */
2109             if (m_at(u.ux + u.dx, u.uy + u.dy) != mon)
2110                 return (boolean) (nsum != 0);
2111             /* Do not print "You hit" message, since known_hitum
2112              * already did it.
2113              */
2114             if (dhit && mattk->adtyp != AD_SPEL && mattk->adtyp != AD_PHYS)
2115                 sum[i] = damageum(mon, mattk);
2116             break;
2117         case AT_CLAW:
2118             if (uwep && !cantwield(youmonst.data) && !weapon_used)
2119                 goto use_weapon;
2120             /*FALLTHRU*/
2121         case AT_TUCH:
2122             if (uwep && youmonst.data->mlet == S_LICH && !weapon_used)
2123                 goto use_weapon;
2124             /*FALLTHRU*/
2125         case AT_KICK:
2126         case AT_BITE:
2127         case AT_STNG:
2128         case AT_BUTT:
2129         case AT_TENT:
2130             tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0,
2131                                    &attknum, &armorpenalty);
2132             dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
2133             if (dhit) {
2134                 int compat;
2135
2136                 if (!u.uswallow
2137                     && (compat = could_seduce(&youmonst, mon, mattk))) {
2138                     You("%s %s %s.",
2139                         mon->mcansee && haseyes(mon->data) ? "smile at"
2140                                                            : "talk to",
2141                         mon_nam(mon),
2142                         compat == 2 ? "engagingly" : "seductively");
2143                     /* doesn't anger it; no wakeup() */
2144                     sum[i] = damageum(mon, mattk);
2145                     break;
2146                 }
2147                 wakeup(mon);
2148                 /* maybe this check should be in damageum()? */
2149                 if (mon->data == &mons[PM_SHADE]
2150                     && !(mattk->aatyp == AT_KICK && uarmf
2151                          && uarmf->blessed)) {
2152                     Your("attack passes harmlessly through %s.",
2153                          mon_nam(mon));
2154                     break;
2155                 }
2156                 if (mattk->aatyp == AT_KICK)
2157                     You("kick %s.", mon_nam(mon));
2158                 else if (mattk->aatyp == AT_BITE)
2159                     You("bite %s.", mon_nam(mon));
2160                 else if (mattk->aatyp == AT_STNG)
2161                     You("sting %s.", mon_nam(mon));
2162                 else if (mattk->aatyp == AT_BUTT)
2163                     You("butt %s.", mon_nam(mon));
2164                 else if (mattk->aatyp == AT_TUCH)
2165                     You("touch %s.", mon_nam(mon));
2166                 else if (mattk->aatyp == AT_TENT)
2167                     Your("tentacles suck %s.", mon_nam(mon));
2168                 else
2169                     You("hit %s.", mon_nam(mon));
2170                 sum[i] = damageum(mon, mattk);
2171             } else {
2172                 missum(mon, mattk, (tmp + armorpenalty > dieroll));
2173             }
2174             break;
2175
2176         case AT_HUGS:
2177             /* automatic if prev two attacks succeed, or if
2178              * already grabbed in a previous attack
2179              */
2180             dhit = 1;
2181             wakeup(mon);
2182             if (mon->data == &mons[PM_SHADE])
2183                 Your("hug passes harmlessly through %s.", mon_nam(mon));
2184             else if (!sticks(mon->data) && !u.uswallow) {
2185                 if (mon == u.ustuck) {
2186                     pline("%s is being %s.", Monnam(mon),
2187                           u.umonnum == PM_ROPE_GOLEM ? "choked" : "crushed");
2188                     sum[i] = damageum(mon, mattk);
2189                 } else if (i >= 2 && sum[i - 1] && sum[i - 2]) {
2190                     You("grab %s!", mon_nam(mon));
2191                     u.ustuck = mon;
2192                     sum[i] = damageum(mon, mattk);
2193                 }
2194             }
2195             break;
2196
2197         case AT_EXPL: /* automatic hit if next to */
2198             dhit = -1;
2199             wakeup(mon);
2200             sum[i] = explum(mon, mattk);
2201             break;
2202
2203         case AT_ENGL:
2204             tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0,
2205                                    &attknum, &armorpenalty);
2206             if ((dhit = (tmp > rnd(20 + i)))) {
2207                 wakeup(mon);
2208                 if (mon->data == &mons[PM_SHADE])
2209                     Your("attempt to surround %s is harmless.", mon_nam(mon));
2210                 else {
2211                     sum[i] = gulpum(mon, mattk);
2212                     if (sum[i] == 2 && (mon->data->mlet == S_ZOMBIE
2213                                         || mon->data->mlet == S_MUMMY)
2214                         && rn2(5) && !Sick_resistance) {
2215                         You_feel("%ssick.", (Sick) ? "very " : "");
2216                         mdamageu(mon, rnd(8));
2217                     }
2218                 }
2219             } else {
2220                 missum(mon, mattk, FALSE);
2221             }
2222             break;
2223
2224         case AT_MAGC:
2225             /* No check for uwep; if wielding nothing we want to
2226              * do the normal 1-2 points bare hand damage...
2227              */
2228             if ((youmonst.data->mlet == S_KOBOLD
2229                  || youmonst.data->mlet == S_ORC
2230                  || youmonst.data->mlet == S_GNOME) && !weapon_used)
2231                 goto use_weapon;
2232
2233         case AT_NONE:
2234         case AT_BOOM:
2235             continue;
2236         /* Not break--avoid passive attacks from enemy */
2237
2238         case AT_BREA:
2239         case AT_SPIT:
2240         case AT_GAZE: /* all done using #monster command */
2241             dhit = 0;
2242             break;
2243
2244         default: /* Strange... */
2245             impossible("strange attack of yours (%d)", mattk->aatyp);
2246         }
2247         if (dhit == -1) {
2248             u.mh = -1; /* dead in the current form */
2249             rehumanize();
2250         }
2251         if (sum[i] == 2)
2252             return (boolean) passive(mon, 1, 0, mattk->aatyp, FALSE);
2253         /* defender dead */
2254         else {
2255             (void) passive(mon, sum[i], 1, mattk->aatyp, FALSE);
2256             nsum |= sum[i];
2257         }
2258         if (!Upolyd)
2259             break; /* No extra attacks if no longer a monster */
2260         if (multi < 0)
2261             break; /* If paralyzed while attacking, i.e. floating eye */
2262     }
2263     return (boolean) (nsum != 0);
2264 }
2265
2266 /*      Special (passive) attacks on you by monsters done here.
2267  */
2268 int
2269 passive(mon, mhit, malive, aatyp, wep_was_destroyed)
2270 register struct monst *mon;
2271 register boolean mhit;
2272 register int malive;
2273 uchar aatyp;
2274 boolean wep_was_destroyed;
2275 {
2276     register struct permonst *ptr = mon->data;
2277     register int i, tmp;
2278
2279     for (i = 0;; i++) {
2280         if (i >= NATTK)
2281             return (malive | mhit); /* no passive attacks */
2282         if (ptr->mattk[i].aatyp == AT_NONE)
2283             break; /* try this one */
2284     }
2285     /* Note: tmp not always used */
2286     if (ptr->mattk[i].damn)
2287         tmp = d((int) ptr->mattk[i].damn, (int) ptr->mattk[i].damd);
2288     else if (ptr->mattk[i].damd)
2289         tmp = d((int) mon->m_lev + 1, (int) ptr->mattk[i].damd);
2290     else
2291         tmp = 0;
2292
2293     /*  These affect you even if they just died.
2294      */
2295     switch (ptr->mattk[i].adtyp) {
2296     case AD_FIRE:
2297         if (mhit && !mon->mcan) {
2298             if (aatyp == AT_KICK) {
2299                 if (uarmf && !rn2(6))
2300                     (void) erode_obj(uarmf, xname(uarmf), ERODE_BURN,
2301                                      EF_GREASE | EF_VERBOSE);
2302             } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2303                        || aatyp == AT_MAGC || aatyp == AT_TUCH)
2304                 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2305         }
2306         break;
2307     case AD_ACID:
2308         if (mhit && rn2(2)) {
2309             if (Blind || !flags.verbose)
2310                 You("are splashed!");
2311             else
2312                 You("are splashed by %s acid!", s_suffix(mon_nam(mon)));
2313
2314             if (!Acid_resistance)
2315                 mdamageu(mon, tmp);
2316             if (!rn2(30))
2317                 erode_armor(&youmonst, ERODE_CORRODE);
2318         }
2319         if (mhit) {
2320             if (aatyp == AT_KICK) {
2321                 if (uarmf && !rn2(6))
2322                     (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
2323                                      EF_GREASE | EF_VERBOSE);
2324             } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2325                        || aatyp == AT_MAGC || aatyp == AT_TUCH)
2326                 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2327         }
2328         exercise(A_STR, FALSE);
2329         break;
2330     case AD_STON:
2331         if (mhit) { /* successful attack */
2332             long protector = attk_protection((int) aatyp);
2333
2334             /* hero using monsters' AT_MAGC attack is hitting hand to
2335                hand rather than casting a spell */
2336             if (aatyp == AT_MAGC)
2337                 protector = W_ARMG;
2338
2339             if (protector == 0L /* no protection */
2340                 || (protector == W_ARMG && !uarmg
2341                     && !uwep && !wep_was_destroyed)
2342                 || (protector == W_ARMF && !uarmf)
2343                 || (protector == W_ARMH && !uarmh)
2344                 || (protector == (W_ARMC | W_ARMG) && (!uarmc || !uarmg))) {
2345                 if (!Stone_resistance
2346                     && !(poly_when_stoned(youmonst.data)
2347                          && polymon(PM_STONE_GOLEM))) {
2348                     done_in_by(mon, STONING); /* "You turn to stone..." */
2349                     return 2;
2350                 }
2351             }
2352         }
2353         break;
2354     case AD_RUST:
2355         if (mhit && !mon->mcan) {
2356             if (aatyp == AT_KICK) {
2357                 if (uarmf)
2358                     (void) erode_obj(uarmf, xname(uarmf), ERODE_RUST,
2359                                      EF_GREASE | EF_VERBOSE);
2360             } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2361                        || aatyp == AT_MAGC || aatyp == AT_TUCH)
2362                 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2363         }
2364         break;
2365     case AD_CORR:
2366         if (mhit && !mon->mcan) {
2367             if (aatyp == AT_KICK) {
2368                 if (uarmf)
2369                     (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
2370                                      EF_GREASE | EF_VERBOSE);
2371             } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2372                        || aatyp == AT_MAGC || aatyp == AT_TUCH)
2373                 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2374         }
2375         break;
2376     case AD_MAGM:
2377         /* wrath of gods for attacking Oracle */
2378         if (Antimagic) {
2379             shieldeff(u.ux, u.uy);
2380             pline("A hail of magic missiles narrowly misses you!");
2381         } else {
2382             You("are hit by magic missiles appearing from thin air!");
2383             mdamageu(mon, tmp);
2384         }
2385         break;
2386     case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
2387         if (mhit) {
2388             struct obj *obj = (struct obj *) 0;
2389
2390             if (aatyp == AT_KICK) {
2391                 obj = uarmf;
2392                 if (!obj)
2393                     break;
2394             } else if (aatyp == AT_BITE || aatyp == AT_BUTT
2395                        || (aatyp >= AT_STNG && aatyp < AT_WEAP)) {
2396                 break; /* no object involved */
2397             }
2398             passive_obj(mon, obj, &(ptr->mattk[i]));
2399         }
2400         break;
2401     default:
2402         break;
2403     }
2404
2405     /*  These only affect you if they still live.
2406      */
2407     if (malive && !mon->mcan && rn2(3)) {
2408         switch (ptr->mattk[i].adtyp) {
2409         case AD_PLYS:
2410             if (ptr == &mons[PM_FLOATING_EYE]) {
2411                 if (!canseemon(mon)) {
2412                     break;
2413                 }
2414                 if (mon->mcansee) {
2415                     if (ureflects("%s gaze is reflected by your %s.",
2416                                   s_suffix(Monnam(mon)))) {
2417                         ;
2418                     } else if (Free_action) {
2419                         You("momentarily stiffen under %s gaze!",
2420                             s_suffix(mon_nam(mon)));
2421                     } else if (Hallucination && rn2(4)) {
2422                         pline("%s looks %s%s.", Monnam(mon),
2423                               !rn2(2) ? "" : "rather ",
2424                               !rn2(2) ? "numb" : "stupified");
2425                     } else {
2426                         You("are frozen by %s gaze!", s_suffix(mon_nam(mon)));
2427                         nomul((ACURR(A_WIS) > 12 || rn2(4)) ? -tmp : -127);
2428                         multi_reason = "frozen by a monster's gaze";
2429                         nomovemsg = 0;
2430                     }
2431                 } else {
2432                     pline("%s cannot defend itself.",
2433                           Adjmonnam(mon, "blind"));
2434                     if (!rn2(500))
2435                         change_luck(-1);
2436                 }
2437             } else if (Free_action) {
2438                 You("momentarily stiffen.");
2439             } else { /* gelatinous cube */
2440                 You("are frozen by %s!", mon_nam(mon));
2441                 nomovemsg = You_can_move_again;
2442                 nomul(-tmp);
2443                 multi_reason = "frozen by a monster";
2444                 exercise(A_DEX, FALSE);
2445             }
2446             break;
2447         case AD_COLD: /* brown mold or blue jelly */
2448             if (monnear(mon, u.ux, u.uy)) {
2449                 if (Cold_resistance) {
2450                     shieldeff(u.ux, u.uy);
2451                     You_feel("a mild chill.");
2452                     ugolemeffects(AD_COLD, tmp);
2453                     break;
2454                 }
2455                 You("are suddenly very cold!");
2456                 mdamageu(mon, tmp);
2457                 /* monster gets stronger with your heat! */
2458                 mon->mhp += tmp / 2;
2459                 if (mon->mhpmax < mon->mhp)
2460                     mon->mhpmax = mon->mhp;
2461                 /* at a certain point, the monster will reproduce! */
2462                 if (mon->mhpmax > ((int) (mon->m_lev + 1) * 8))
2463                     (void) split_mon(mon, &youmonst);
2464             }
2465             break;
2466         case AD_STUN: /* specifically yellow mold */
2467             if (!Stunned)
2468                 make_stunned((long) tmp, TRUE);
2469             break;
2470         case AD_FIRE:
2471             if (monnear(mon, u.ux, u.uy)) {
2472                 if (Fire_resistance) {
2473                     shieldeff(u.ux, u.uy);
2474                     You_feel("mildly warm.");
2475                     ugolemeffects(AD_FIRE, tmp);
2476                     break;
2477                 }
2478                 You("are suddenly very hot!");
2479                 mdamageu(mon, tmp); /* fire damage */
2480             }
2481             break;
2482         case AD_ELEC:
2483             if (Shock_resistance) {
2484                 shieldeff(u.ux, u.uy);
2485                 You_feel("a mild tingle.");
2486                 ugolemeffects(AD_ELEC, tmp);
2487                 break;
2488             }
2489             You("are jolted with electricity!");
2490             mdamageu(mon, tmp);
2491             break;
2492         default:
2493             break;
2494         }
2495     }
2496     return (malive | mhit);
2497 }
2498
2499 /*
2500  * Special (passive) attacks on an attacking object by monsters done here.
2501  * Assumes the attack was successful.
2502  */
2503 void
2504 passive_obj(mon, obj, mattk)
2505 register struct monst *mon;
2506 register struct obj *obj; /* null means pick uwep, uswapwep or uarmg */
2507 struct attack *mattk;     /* null means we find one internally */
2508 {
2509     struct permonst *ptr = mon->data;
2510     register int i;
2511
2512     /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */
2513     if (!obj) {
2514         obj = (u.twoweap && uswapwep && !rn2(2)) ? uswapwep : uwep;
2515         if (!obj && mattk->adtyp == AD_ENCH)
2516             obj = uarmg; /* no weapon? then must be gloves */
2517         if (!obj)
2518             return; /* no object to affect */
2519     }
2520
2521     /* if caller hasn't specified an attack, find one */
2522     if (!mattk) {
2523         for (i = 0;; i++) {
2524             if (i >= NATTK)
2525                 return; /* no passive attacks */
2526             if (ptr->mattk[i].aatyp == AT_NONE)
2527                 break; /* try this one */
2528         }
2529         mattk = &(ptr->mattk[i]);
2530     }
2531
2532     switch (mattk->adtyp) {
2533     case AD_FIRE:
2534         if (!rn2(6) && !mon->mcan) {
2535             (void) erode_obj(obj, NULL, ERODE_BURN, EF_NONE);
2536         }
2537         break;
2538     case AD_ACID:
2539         if (!rn2(6)) {
2540             (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
2541         }
2542         break;
2543     case AD_RUST:
2544         if (!mon->mcan) {
2545             (void) erode_obj(obj, NULL, ERODE_RUST, EF_NONE);
2546         }
2547         break;
2548     case AD_CORR:
2549         if (!mon->mcan) {
2550             (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
2551         }
2552         break;
2553     case AD_ENCH:
2554         if (!mon->mcan) {
2555             if (drain_item(obj) && carried(obj)
2556                 && (obj->known || obj->oclass == ARMOR_CLASS)) {
2557                 pline("%s less effective.", Yobjnam2(obj, "seem"));
2558             }
2559             break;
2560         }
2561     default:
2562         break;
2563     }
2564
2565     if (carried(obj))
2566         update_inventory();
2567 }
2568
2569 /* Note: caller must ascertain mtmp is mimicking... */
2570 void
2571 stumble_onto_mimic(mtmp)
2572 struct monst *mtmp;
2573 {
2574     const char *fmt = "Wait!  That's %s!", *generic = "a monster", *what = 0;
2575
2576     if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK))
2577         u.ustuck = mtmp;
2578
2579     if (Blind) {
2580         if (!Blind_telepat)
2581             what = generic; /* with default fmt */
2582         else if (mtmp->m_ap_type == M_AP_MONSTER)
2583             what = a_monnam(mtmp); /* differs from what was sensed */
2584     } else {
2585         int glyph = levl[u.ux + u.dx][u.uy + u.dy].glyph;
2586
2587         if (glyph_is_cmap(glyph) && (glyph_to_cmap(glyph) == S_hcdoor
2588                                      || glyph_to_cmap(glyph) == S_vcdoor))
2589             fmt = "The door actually was %s!";
2590         else if (glyph_is_object(glyph) && glyph_to_obj(glyph) == GOLD_PIECE)
2591             fmt = "That gold was %s!";
2592
2593         /* cloned Wiz starts out mimicking some other monster and
2594            might make himself invisible before being revealed */
2595         if (mtmp->minvis && !See_invisible)
2596             what = generic;
2597         else
2598             what = a_monnam(mtmp);
2599     }
2600     if (what)
2601         pline(fmt, what);
2602
2603     wakeup(mtmp); /* clears mimicking */
2604     /* if hero is blind, wakeup() won't display the monster even though
2605        it's no longer concealed */
2606     if (!canspotmon(mtmp)
2607         && !glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
2608         map_invisible(mtmp->mx, mtmp->my);
2609 }
2610
2611 STATIC_OVL void
2612 nohandglow(mon)
2613 struct monst *mon;
2614 {
2615     char *hands = makeplural(body_part(HAND));
2616
2617     if (!u.umconf || mon->mconf)
2618         return;
2619     if (u.umconf == 1) {
2620         if (Blind)
2621             Your("%s stop tingling.", hands);
2622         else
2623             Your("%s stop glowing %s.", hands, hcolor(NH_RED));
2624     } else {
2625         if (Blind)
2626             pline_The("tingling in your %s lessens.", hands);
2627         else
2628             Your("%s no longer glow so brightly %s.", hands, hcolor(NH_RED));
2629     }
2630     u.umconf--;
2631 }
2632
2633 int
2634 flash_hits_mon(mtmp, otmp)
2635 struct monst *mtmp;
2636 struct obj *otmp; /* source of flash */
2637 {
2638     int tmp, amt, res = 0, useeit = canseemon(mtmp);
2639
2640     if (mtmp->msleeping) {
2641         mtmp->msleeping = 0;
2642         if (useeit) {
2643             pline_The("flash awakens %s.", mon_nam(mtmp));
2644             res = 1;
2645         }
2646     } else if (mtmp->data->mlet != S_LIGHT) {
2647         if (!resists_blnd(mtmp)) {
2648             tmp = dist2(otmp->ox, otmp->oy, mtmp->mx, mtmp->my);
2649             if (useeit) {
2650                 pline("%s is blinded by the flash!", Monnam(mtmp));
2651                 res = 1;
2652             }
2653             if (mtmp->data == &mons[PM_GREMLIN]) {
2654                 /* Rule #1: Keep them out of the light. */
2655                 amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4)
2656                                               : rn2(min(mtmp->mhp, 4));
2657                 light_hits_gremlin(mtmp, amt);
2658             }
2659             if (mtmp->mhp > 0) {
2660                 if (!context.mon_moving)
2661                     setmangry(mtmp);
2662                 if (tmp < 9 && !mtmp->isshk && rn2(4))
2663                     monflee(mtmp, rn2(4) ? rnd(100) : 0, FALSE, TRUE);
2664                 mtmp->mcansee = 0;
2665                 mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50 / tmp);
2666             }
2667         }
2668     }
2669     return res;
2670 }
2671
2672 void
2673 light_hits_gremlin(mon, dmg)
2674 struct monst *mon;
2675 int dmg;
2676 {
2677     pline("%s %s!", Monnam(mon),
2678           (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain");
2679     if ((mon->mhp -= dmg) <= 0) {
2680         if (context.mon_moving)
2681             monkilled(mon, (char *) 0, AD_BLND);
2682         else
2683             killed(mon);
2684     } else if (cansee(mon->mx, mon->my) && !canspotmon(mon)) {
2685         map_invisible(mon->mx, mon->my);
2686     }
2687 }
2688
2689 /*uhitm.c*/