OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / mhitu.c
1 /*      SCCS Id: @(#)mhitu.c    3.4     2003/11/26      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6 #include "artifact.h"
7
8 STATIC_VAR NEARDATA struct obj *otmp;
9
10 STATIC_DCL void FDECL(urustm, (struct monst *, struct obj *));
11 # ifdef OVL1
12 STATIC_DCL boolean FDECL(u_slip_free, (struct monst *,struct attack *));
13 STATIC_DCL int FDECL(passiveum, (struct permonst *,struct monst *,struct attack *));
14 # endif /* OVL1 */
15
16 #ifdef OVLB
17 # ifdef SEDUCE
18 STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
19 # endif
20 #endif /* OVLB */
21
22 STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
23 STATIC_DCL int FDECL(hitmu, (struct monst *,struct attack *));
24 STATIC_DCL int FDECL(gulpmu, (struct monst *,struct attack *));
25 STATIC_DCL int FDECL(explmu, (struct monst *,struct attack *,BOOLEAN_P));
26 STATIC_DCL void FDECL(missmu,(struct monst *,BOOLEAN_P,struct attack *));
27 STATIC_DCL void FDECL(mswings,(struct monst *,struct obj *));
28 STATIC_DCL void FDECL(wildmiss, (struct monst *,struct attack *));
29
30 STATIC_DCL void FDECL(hurtarmor,(int));
31 STATIC_DCL void FDECL(hitmsg,(struct monst *,struct attack *));
32
33 /* See comment in mhitm.c.  If we use this a lot it probably should be */
34 /* changed to a parameter to mhitu. */
35 static int dieroll;
36
37 #ifdef OVL1
38
39
40 STATIC_OVL void
41 hitmsg(mtmp, mattk)
42 register struct monst *mtmp;
43 register struct attack *mattk;
44 {
45         int compat;
46
47         /* Note: if opposite gender, "seductively" */
48         /* If same gender, "engagingly" for nymph, normal msg for others */
49         if((compat = could_seduce(mtmp, &youmonst, mattk))
50                         && !mtmp->mcan && !mtmp->mspec_used) {
51                 pline("%s %s you %s.", Monnam(mtmp),
52                         Blind ? "talks to" : "smiles at",
53                         compat == 2 ? "engagingly" : "seductively");
54         } else
55             switch (mattk->aatyp) {
56                 case AT_BITE:
57                         pline("%s bites!", Monnam(mtmp));
58                         break;
59                 case AT_KICK:
60                         pline("%s kicks%c", Monnam(mtmp),
61                                     thick_skinned(youmonst.data) ? '.' : '!');
62                         break;
63                 case AT_STNG:
64                         pline("%s stings!", Monnam(mtmp));
65                         break;
66                 case AT_BUTT:
67                         pline("%s butts!", Monnam(mtmp));
68                         break;
69                 case AT_TUCH:
70                         pline("%s touches you!", Monnam(mtmp));
71                         break;
72                 case AT_TENT:
73                         pline("%s tentacles suck you!",
74                                         s_suffix(Monnam(mtmp)));
75                         break;
76                 case AT_EXPL:
77                 case AT_BOOM:
78                         pline("%s explodes!", Monnam(mtmp));
79                         break;
80                 default:
81                         pline("%s hits!", Monnam(mtmp));
82             }
83 }
84
85 STATIC_OVL void
86 missmu(mtmp, nearmiss, mattk)           /* monster missed you */
87 register struct monst *mtmp;
88 register boolean nearmiss;
89 register struct attack *mattk;
90 {
91         if (!canspotmon(mtmp))
92             map_invisible(mtmp->mx, mtmp->my);
93
94         if(could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan)
95             pline("%s pretends to be friendly.", Monnam(mtmp));
96         else {
97             if (!flags.verbose || !nearmiss)
98                 pline("%s misses.", Monnam(mtmp));
99             else
100                 pline("%s just misses!", Monnam(mtmp));
101         }
102         stop_occupation();
103 }
104
105 STATIC_OVL void
106 mswings(mtmp, otemp)            /* monster swings obj */
107 register struct monst *mtmp;
108 register struct obj *otemp;
109 {
110         if (!flags.verbose || Blind || !mon_visible(mtmp))
111                 return;
112         pline("%s %s %s %s.", Monnam(mtmp),
113               (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
114               mhis(mtmp), singular(otemp, xname));
115 }
116
117 /* return how a poison attack was delivered */
118 const char *
119 mpoisons_subj(mtmp, mattk)
120 struct monst *mtmp;
121 struct attack *mattk;
122 {
123         if (mattk->aatyp == AT_WEAP) {
124             struct obj *mwep = (mtmp == &youmonst) ? uwep : MON_WEP(mtmp);
125             /* "Foo's attack was poisoned." is pretty lame, but at least
126                it's better than "sting" when not a stinging attack... */
127             return (!mwep || !mwep->opoisoned) ? "attack" : "weapon";
128         } else {
129             return (mattk->aatyp == AT_TUCH) ? "contact" :
130                    (mattk->aatyp == AT_GAZE) ? "gaze" :
131                    (mattk->aatyp == AT_BITE) ? "bite" : "sting";
132         }
133 }
134
135 /* called when your intrinsic speed is taken away */
136 void
137 u_slow_down()
138 {
139         HFast = 0L;
140         if (!Fast)
141             You("slow down.");
142         else    /* speed boots */
143             Your("quickness feels less natural.");
144         exercise(A_DEX, FALSE);
145 }
146
147 #endif /* OVL1 */
148 #ifdef OVLB
149
150 STATIC_OVL void
151 wildmiss(mtmp, mattk)           /* monster attacked your displaced image */
152         register struct monst *mtmp;
153         register struct attack *mattk;
154 {
155         int compat;
156
157         /* no map_invisible() -- no way to tell where _this_ is coming from */
158
159         if (!flags.verbose) return;
160         if (!cansee(mtmp->mx, mtmp->my)) return;
161                 /* maybe it's attacking an image around the corner? */
162
163         compat = (mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX) &&
164                  could_seduce(mtmp, &youmonst, (struct attack *)0);
165
166         if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
167             const char *swings =
168                 mattk->aatyp == AT_BITE ? "snaps" :
169                 mattk->aatyp == AT_KICK ? "kicks" :
170                 (mattk->aatyp == AT_STNG ||
171                  mattk->aatyp == AT_BUTT ||
172                  nolimbs(mtmp->data)) ? "lunges" : "swings";
173
174             if (compat)
175                 pline("%s tries to touch you and misses!", Monnam(mtmp));
176             else
177                 switch(rn2(3)) {
178                 case 0: pline("%s %s wildly and misses!", Monnam(mtmp),
179                               swings);
180                     break;
181                 case 1: pline("%s attacks a spot beside you.", Monnam(mtmp));
182                     break;
183                 case 2: pline("%s strikes at %s!", Monnam(mtmp),
184                                 levl[mtmp->mux][mtmp->muy].typ == WATER
185                                     ? "empty water" : "thin air");
186                     break;
187                 default:pline("%s %s wildly!", Monnam(mtmp), swings);
188                     break;
189                 }
190
191         } else if (Displaced) {
192             if (compat)
193                 pline("%s smiles %s at your %sdisplaced image...",
194                         Monnam(mtmp),
195                         compat == 2 ? "engagingly" : "seductively",
196                         Invis ? "invisible " : "");
197             else
198                 pline("%s strikes at your %sdisplaced image and misses you!",
199                         /* Note: if you're both invisible and displaced,
200                          * only monsters which see invisible will attack your
201                          * displaced image, since the displaced image is also
202                          * invisible.
203                          */
204                         Monnam(mtmp),
205                         Invis ? "invisible " : "");
206
207         } else if (Underwater) {
208             /* monsters may miss especially on water level where
209                bubbles shake the player here and there */
210             if (compat)
211                 pline("%s reaches towards your distorted image.",Monnam(mtmp));
212             else
213                 pline("%s is fooled by water reflections and misses!",Monnam(mtmp));
214
215         } else impossible("%s attacks you without knowing your location?",
216                 Monnam(mtmp));
217 }
218
219 void
220 expels(mtmp, mdat, message)
221 register struct monst *mtmp;
222 register struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */
223 boolean message;
224 {
225         if (message) {
226                 if (is_animal(mdat))
227                         You("get regurgitated!");
228                 else {
229                         char blast[40];
230                         register int i;
231
232                         blast[0] = '\0';
233                         for(i = 0; i < NATTK; i++)
234                                 if(mdat->mattk[i].aatyp == AT_ENGL)
235                                         break;
236                         if (mdat->mattk[i].aatyp != AT_ENGL)
237                               impossible("Swallower has no engulfing attack?");
238                         else {
239                                 if (is_whirly(mdat)) {
240                                         switch (mdat->mattk[i].adtyp) {
241                                                 case AD_ELEC:
242                                                         Strcpy(blast,
243                                                       " in a shower of sparks");
244                                                         break;
245                                                 case AD_COLD:
246                                                         Strcpy(blast,
247                                                         " in a blast of frost");
248                                                         break;
249                                         }
250                                 } else
251                                         Strcpy(blast, " with a squelch");
252                                 You("get expelled from %s%s!",
253                                     mon_nam(mtmp), blast);
254                         }
255                 }
256         }
257         unstuck(mtmp);  /* ball&chain returned in unstuck() */
258         mnexto(mtmp);
259         newsym(u.ux,u.uy);
260         spoteffects(TRUE);
261         /* to cover for a case where mtmp is not in a next square */
262         if(um_dist(mtmp->mx,mtmp->my,1))
263                 pline("Brrooaa...  You land hard at some distance.");
264 }
265
266 #endif /* OVLB */
267 #ifdef OVL0
268
269 /* select a monster's next attack, possibly substituting for its usual one */
270 struct attack *
271 getmattk(mptr, indx, prev_result, alt_attk_buf)
272 struct permonst *mptr;
273 int indx, prev_result[];
274 struct attack *alt_attk_buf;
275 {
276     struct attack *attk = &mptr->mattk[indx];
277
278     /* prevent a monster with two consecutive disease or hunger attacks
279        from hitting with both of them on the same turn; if the first has
280        already hit, switch to a stun attack for the second */
281     if (indx > 0 && prev_result[indx - 1] > 0 &&
282             (attk->adtyp == AD_DISE ||
283                 attk->adtyp == AD_PEST ||
284                 attk->adtyp == AD_FAMN) &&
285             attk->adtyp == mptr->mattk[indx - 1].adtyp) {
286         *alt_attk_buf = *attk;
287         attk = alt_attk_buf;
288         attk->adtyp = AD_STUN;
289     }
290     return attk;
291 }
292
293 /*
294  * mattacku: monster attacks you
295  *      returns 1 if monster dies (e.g. "yellow light"), 0 otherwise
296  *      Note: if you're displaced or invisible the monster might attack the
297  *              wrong position...
298  *      Assumption: it's attacking you or an empty square; if there's another
299  *              monster which it attacks by mistake, the caller had better
300  *              take care of it...
301  */
302 int
303 mattacku(mtmp)
304         register struct monst *mtmp;
305 {
306         struct  attack  *mattk, alt_attk;
307         int     i, j, tmp, sum[NATTK];
308         struct  permonst *mdat = mtmp->data;
309         boolean ranged = (distu(mtmp->mx, mtmp->my) > 3);
310                 /* Is it near you?  Affects your actions */
311         boolean range2 = !monnear(mtmp, mtmp->mux, mtmp->muy);
312                 /* Does it think it's near you?  Affects its actions */
313         boolean foundyou = (mtmp->mux==u.ux && mtmp->muy==u.uy);
314                 /* Is it attacking you or your image? */
315         boolean youseeit = canseemon(mtmp);
316                 /* Might be attacking your image around the corner, or
317                  * invisible, or you might be blind....
318                  */
319         
320         if(!ranged) nomul(0);
321         if(mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data)))
322             return(0);
323
324         /* If swallowed, can only be affected by u.ustuck */
325         if(u.uswallow) {
326             if(mtmp != u.ustuck)
327                 return(0);
328             u.ustuck->mux = u.ux;
329             u.ustuck->muy = u.uy;
330             range2 = 0;
331             foundyou = 1;
332             if(u.uinvulnerable) return (0); /* stomachs can't hurt you! */
333         }
334
335 #ifdef STEED
336         else if (u.usteed) {
337                 if (mtmp == u.usteed)
338                         /* Your steed won't attack you */
339                         return (0);
340                 /* Orcs like to steal and eat horses and the like */
341                 if (!rn2(is_orc(mtmp->data) ? 2 : 4) &&
342                                 distu(mtmp->mx, mtmp->my) <= 2) {
343                         /* Attack your steed instead */
344                         i = mattackm(mtmp, u.usteed);
345                         if ((i & MM_AGR_DIED))
346                                 return (1);
347                         if (i & MM_DEF_DIED || u.umoved)
348                                 return (0);
349                         /* Let your steed retaliate */
350                         return (!!(mattackm(u.usteed, mtmp) & MM_DEF_DIED));
351                 }
352         }
353 #endif
354
355         if (u.uundetected && !range2 && foundyou && !u.uswallow) {
356                 u.uundetected = 0;
357                 if (is_hider(youmonst.data)) {
358                     coord cc; /* maybe we need a unexto() function? */
359                     struct obj *obj;
360
361                     You("fall from the %s!", ceiling(u.ux,u.uy));
362                     if (enexto(&cc, u.ux, u.uy, youmonst.data)) {
363                         remove_monster(mtmp->mx, mtmp->my);
364                         newsym(mtmp->mx,mtmp->my);
365                         place_monster(mtmp, u.ux, u.uy);
366                         if(mtmp->wormno) worm_move(mtmp);
367                         teleds(cc.x, cc.y, TRUE);
368                         set_apparxy(mtmp);
369                         newsym(u.ux,u.uy);
370                     } else {
371                         pline("%s is killed by a falling %s (you)!",
372                                         Monnam(mtmp), youmonst.data->mname);
373                         killed(mtmp);
374                         newsym(u.ux,u.uy);
375                         if (mtmp->mhp > 0) return 0;
376                         else return 1;
377                     }
378                     if (youmonst.data->mlet != S_PIERCER)
379                         return(0);      /* trappers don't attack */
380
381                     obj = which_armor(mtmp, WORN_HELMET);
382                     if (obj && is_metallic(obj)) {
383                         Your("blow glances off %s helmet.",
384                                        s_suffix(mon_nam(mtmp)));
385                     } else {
386                         if (3 + find_mac(mtmp) <= rnd(20)) {
387                             pline("%s is hit by a falling piercer (you)!",
388                                                                 Monnam(mtmp));
389                             if ((mtmp->mhp -= d(3,6)) < 1)
390                                 killed(mtmp);
391                         } else
392                           pline("%s is almost hit by a falling piercer (you)!",
393                                                                 Monnam(mtmp));
394                     }
395                 } else {
396                     if (!youseeit)
397                         pline("It tries to move where you are hiding.");
398                     else {
399                         /* Ugly kludge for eggs.  The message is phrased so as
400                          * to be directed at the monster, not the player,
401                          * which makes "laid by you" wrong.  For the
402                          * parallelism to work, we can't rephrase it, so we
403                          * zap the "laid by you" momentarily instead.
404                          */
405                         struct obj *obj = level.objects[u.ux][u.uy];
406
407                         if (obj ||
408                               (youmonst.data->mlet == S_EEL && is_pool(u.ux, u.uy))) {
409                             int save_spe = 0; /* suppress warning */
410                             if (obj) {
411                                 save_spe = obj->spe;
412                                 if (obj->otyp == EGG) obj->spe = 0;
413                             }
414                             if (youmonst.data->mlet == S_EEL)
415                 pline("Wait, %s!  There's a hidden %s named %s there!",
416                                 m_monnam(mtmp), youmonst.data->mname, plname);
417                             else
418              pline("Wait, %s!  There's a %s named %s hiding under %s!",
419                                 m_monnam(mtmp), youmonst.data->mname, plname,
420                                 doname(level.objects[u.ux][u.uy]));
421                             if (obj) obj->spe = save_spe;
422                         } else
423                             impossible("hiding under nothing?");
424                     }
425                     newsym(u.ux,u.uy);
426                 }
427                 return(0);
428         }
429         if (youmonst.data->mlet == S_MIMIC && youmonst.m_ap_type &&
430                     !range2 && foundyou && !u.uswallow) {
431                 if (!youseeit) pline("It gets stuck on you.");
432                 else pline("Wait, %s!  That's a %s named %s!",
433                            m_monnam(mtmp), youmonst.data->mname, plname);
434                 u.ustuck = mtmp;
435                 youmonst.m_ap_type = M_AP_NOTHING;
436                 youmonst.mappearance = 0;
437                 newsym(u.ux,u.uy);
438                 return(0);
439         }
440
441         /* player might be mimicking an object */
442         if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou && !u.uswallow) {
443             if (!youseeit)
444                  pline("%s %s!", Something,
445                         (likes_gold(mtmp->data) && youmonst.mappearance == GOLD_PIECE) ?
446                         "tries to pick you up" : "disturbs you");
447             else pline("Wait, %s!  That %s is really %s named %s!",
448                         m_monnam(mtmp),
449                         mimic_obj_name(&youmonst),
450                         an(mons[u.umonnum].mname),
451                         plname);
452             if (multi < 0) {    /* this should always be the case */
453                 char buf[BUFSZ];
454                 Sprintf(buf, "You appear to be %s again.",
455                         Upolyd ? (const char *) an(youmonst.data->mname) :
456                             (const char *) "yourself");
457                 unmul(buf);     /* immediately stop mimicking */
458             }
459             return 0;
460         }
461
462 /*      Work out the armor class differential   */
463         tmp = AC_VALUE(u.uac) + 10;             /* tmp ~= 0 - 20 */
464         tmp += mtmp->m_lev;
465         if(multi < 0) tmp += 4;
466         if((Invis && !perceives(mdat)) || !mtmp->mcansee)
467                 tmp -= 2;
468         if(mtmp->mtrapped) tmp -= 2;
469         if(tmp <= 0) tmp = 1;
470
471         /* make eels visible the moment they hit/miss us */
472         if(mdat->mlet == S_EEL && mtmp->minvis && cansee(mtmp->mx,mtmp->my)) {
473                 mtmp->minvis = 0;
474                 newsym(mtmp->mx,mtmp->my);
475         }
476
477 /*      Special demon handling code */
478         if(!mtmp->cham && is_demon(mdat) && !range2
479            && mtmp->data != &mons[PM_BALROG]
480            && mtmp->data != &mons[PM_SUCCUBUS]
481            && mtmp->data != &mons[PM_INCUBUS])
482             if(!mtmp->mcan && !rn2(13)) msummon(mtmp);
483
484 /*      Special lycanthrope handling code */
485         if(!mtmp->cham && is_were(mdat) && !range2) {
486
487             if(is_human(mdat)) {
488                 if(!rn2(5 - (night() * 2)) && !mtmp->mcan) new_were(mtmp);
489             } else if(!rn2(30) && !mtmp->mcan) new_were(mtmp);
490             mdat = mtmp->data;
491
492             if(!rn2(10) && !mtmp->mcan) {
493                 int numseen, numhelp;
494                 char buf[BUFSZ], genericwere[BUFSZ];
495
496                 Strcpy(genericwere, "creature");
497                 numhelp = were_summon(mdat, FALSE, &numseen, genericwere);
498                 if (youseeit) {
499                         pline("%s summons help!", Monnam(mtmp));
500                         if (numhelp > 0) {
501                             if (numseen == 0)
502                                 You_feel("hemmed in.");
503                         } else pline("But none comes.");
504                 } else {
505                         const char *from_nowhere;
506
507                         if (flags.soundok) {
508                                 pline("%s %s!", Something,
509                                         makeplural(growl_sound(mtmp)));
510                                 from_nowhere = "";
511                         } else from_nowhere = " from nowhere";
512                         if (numhelp > 0) {
513                             if (numseen < 1) You_feel("hemmed in.");
514                             else {
515                                 if (numseen == 1)
516                                         Sprintf(buf, "%s appears",
517                                                         an(genericwere));
518                                 else
519                                         Sprintf(buf, "%s appear",
520                                                         makeplural(genericwere));
521                                 pline("%s%s!", upstart(buf), from_nowhere);
522                             }
523                         } /* else no help came; but you didn't know it tried */
524                 }
525             }
526         }
527
528         if(u.uinvulnerable) {
529             /* monsters won't attack you */
530             if(mtmp == u.ustuck)
531                 pline("%s loosens its grip slightly.", Monnam(mtmp));
532             else if(!range2) {
533                 if (youseeit || sensemon(mtmp))
534                     pline("%s starts to attack you, but pulls back.",
535                           Monnam(mtmp));
536                 else
537                     You_feel("%s move nearby.", something);
538             }
539             return (0);
540         }
541
542         /* Unlike defensive stuff, don't let them use item _and_ attack. */
543         if(find_offensive(mtmp)) {
544                 int foo = use_offensive(mtmp);
545
546                 if (foo != 0) return(foo==1);
547         }
548
549         for(i = 0; i < NATTK; i++) {
550
551             sum[i] = 0;
552             mattk = getmattk(mdat, i, sum, &alt_attk);
553             if (u.uswallow && (mattk->aatyp != AT_ENGL))
554                 continue;
555             switch(mattk->aatyp) {
556                 case AT_CLAW:   /* "hand to hand" attacks */
557                 case AT_KICK:
558                 case AT_BITE:
559                 case AT_STNG:
560                 case AT_TUCH:
561                 case AT_BUTT:
562                 case AT_TENT:
563                         if(!range2 && (!MON_WEP(mtmp) || mtmp->mconf || Conflict ||
564                                         !touch_petrifies(youmonst.data))) {
565                             if (foundyou) {
566                                 if(tmp > (j = rnd(20+i))) {
567                                     if (mattk->aatyp != AT_KICK ||
568                                             !thick_skinned(youmonst.data))
569                                         sum[i] = hitmu(mtmp, mattk);
570                                 } else
571                                     missmu(mtmp, (tmp == j), mattk);
572                             } else
573                                 wildmiss(mtmp, mattk);
574                         }
575                         break;
576
577                 case AT_HUGS:   /* automatic if prev two attacks succeed */
578                         /* Note: if displaced, prev attacks never succeeded */
579                         if((!range2 && i>=2 && sum[i-1] && sum[i-2])
580                                                         || mtmp == u.ustuck)
581                                 sum[i]= hitmu(mtmp, mattk);
582                         break;
583
584                 case AT_GAZE:   /* can affect you either ranged or not */
585                         /* Medusa gaze already operated through m_respond in
586                          * dochug(); don't gaze more than once per round.
587                          */
588                         if (mdat != &mons[PM_MEDUSA])
589                                 sum[i] = gazemu(mtmp, mattk);
590                         break;
591
592                 case AT_EXPL:   /* automatic hit if next to, and aimed at you */
593                         if(!range2) sum[i] = explmu(mtmp, mattk, foundyou);
594                         break;
595
596                 case AT_ENGL:
597                         if (!range2) {
598                             if(foundyou) {
599                                 if(u.uswallow || tmp > (j = rnd(20+i))) {
600                                     /* Force swallowing monster to be
601                                      * displayed even when player is
602                                      * moving away */
603                                     flush_screen(1);
604                                     sum[i] = gulpmu(mtmp, mattk);
605                                 } else {
606                                     missmu(mtmp, (tmp == j), mattk);
607                                 }
608                             } else if (is_animal(mtmp->data)) {
609                                 pline("%s gulps some air!", Monnam(mtmp));
610                             } else {
611                                 if (youseeit)
612                                     pline("%s lunges forward and recoils!",
613                                           Monnam(mtmp));
614                                 else
615                                     You_hear("a %s nearby.",
616                                              is_whirly(mtmp->data) ?
617                                                 "rushing noise" : "splat");
618                            }
619                         }
620                         break;
621                 case AT_BREA:
622                         if(range2) sum[i] = breamu(mtmp, mattk);
623                         /* Note: breamu takes care of displacement */
624                         break;
625                 case AT_SPIT:
626                         if(range2) sum[i] = spitmu(mtmp, mattk);
627                         /* Note: spitmu takes care of displacement */
628                         break;
629                 case AT_WEAP:
630                         if(range2) {
631 #ifdef REINCARNATION
632                                 if (!Is_rogue_level(&u.uz))
633 #endif
634                                         thrwmu(mtmp);
635                         } else {
636                             int hittmp = 0;
637
638                             /* Rare but not impossible.  Normally the monster
639                              * wields when 2 spaces away, but it can be
640                              * teleported or whatever....
641                              */
642                             if (mtmp->weapon_check == NEED_WEAPON ||
643                                                         !MON_WEP(mtmp)) {
644                                 mtmp->weapon_check = NEED_HTH_WEAPON;
645                                 /* mon_wield_item resets weapon_check as
646                                  * appropriate */
647                                 if (mon_wield_item(mtmp) != 0) break;
648                             }
649                             if (foundyou) {
650                                 otmp = MON_WEP(mtmp);
651                                 if(otmp) {
652                                     hittmp = hitval(otmp, &youmonst);
653                                     tmp += hittmp;
654                                     mswings(mtmp, otmp);
655                                 }
656                                 if(tmp > (j = dieroll = rnd(20+i)))
657                                     sum[i] = hitmu(mtmp, mattk);
658                                 else
659                                     missmu(mtmp, (tmp == j), mattk);
660                                 /* KMH -- Don't accumulate to-hit bonuses */
661                                 if (otmp)
662                                         tmp -= hittmp;
663                             } else
664                                 wildmiss(mtmp, mattk);
665                         }
666                         break;
667                 case AT_MAGC:
668                         if (range2)
669                             sum[i] = buzzmu(mtmp, mattk);
670                         else {
671                             if (foundyou)
672                                 sum[i] = castmu(mtmp, mattk, TRUE, TRUE);
673                             else
674                                 sum[i] = castmu(mtmp, mattk, TRUE, FALSE);
675                         }
676                         break;
677
678                 default:                /* no attack */
679                         break;
680             }
681             if(flags.botl) bot();
682         /* give player a chance of waking up before dying -kaa */
683             if(sum[i] == 1) {       /* successful attack */
684                 if (u.usleep && u.usleep < monstermoves && !rn2(10)) {
685                     multi = -1;
686                     nomovemsg = "The combat suddenly awakens you.";
687                 }
688             }
689             if(sum[i] == 2) return 1;           /* attacker dead */
690             if(sum[i] == 3) break;  /* attacker teleported, no more attacks */
691             /* sum[i] == 0: unsuccessful attack */
692         }
693         return(0);
694 }
695
696 #endif /* OVL0 */
697 #ifdef OVLB
698
699 /*
700  * helper function for some compilers that have trouble with hitmu
701  */
702
703 STATIC_OVL void
704 hurtarmor(attk)
705 int attk;
706 {
707         int     hurt;
708
709         switch(attk) {
710             /* 0 is burning, which we should never be called with */
711             case AD_RUST: hurt = 1; break;
712             case AD_CORR: hurt = 3; break;
713             default: hurt = 2; break;
714         }
715
716         /* What the following code does: it keeps looping until it
717          * finds a target for the rust monster.
718          * Head, feet, etc... not covered by metal, or covered by
719          * rusty metal, are not targets.  However, your body always
720          * is, no matter what covers it.
721          */
722         while (1) {
723             switch(rn2(5)) {
724             case 0:
725                 if (!uarmh || !rust_dmg(uarmh, xname(uarmh), hurt, FALSE, &youmonst))
726                         continue;
727                 break;
728             case 1:
729                 if (uarmc) {
730                     (void)rust_dmg(uarmc, xname(uarmc), hurt, TRUE, &youmonst);
731                     break;
732                 }
733                 /* Note the difference between break and continue;
734                  * break means it was hit and didn't rust; continue
735                  * means it wasn't a target and though it didn't rust
736                  * something else did.
737                  */
738                 if (uarm)
739                     (void)rust_dmg(uarm, xname(uarm), hurt, TRUE, &youmonst);
740 #ifdef TOURIST
741                 else if (uarmu)
742                     (void)rust_dmg(uarmu, xname(uarmu), hurt, TRUE, &youmonst);
743 #endif
744                 break;
745             case 2:
746                 if (!uarms || !rust_dmg(uarms, xname(uarms), hurt, FALSE, &youmonst))
747                     continue;
748                 break;
749             case 3:
750                 if (!uarmg || !rust_dmg(uarmg, xname(uarmg), hurt, FALSE, &youmonst))
751                     continue;
752                 break;
753             case 4:
754                 if (!uarmf || !rust_dmg(uarmf, xname(uarmf), hurt, FALSE, &youmonst))
755                     continue;
756                 break;
757             }
758             break; /* Out of while loop */
759         }
760 }
761
762 #endif /* OVLB */
763 #ifdef OVL1
764
765 STATIC_OVL boolean
766 diseasemu(mdat)
767 struct permonst *mdat;
768 {
769         if (Sick_resistance) {
770                 You_feel("a slight illness.");
771                 return FALSE;
772         } else {
773                 make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON), 20),
774                         mdat->mname, TRUE, SICK_NONVOMITABLE);
775                 return TRUE;
776         }
777 }
778
779 /* check whether slippery clothing protects from hug or wrap attack */
780 STATIC_OVL boolean
781 u_slip_free(mtmp, mattk)
782 struct monst *mtmp;
783 struct attack *mattk;
784 {
785         struct obj *obj = (uarmc ? uarmc : uarm);
786
787 #ifdef TOURIST
788         if (!obj) obj = uarmu;
789 #endif
790         if (mattk->adtyp == AD_DRIN) obj = uarmh;
791
792         /* if your cloak/armor is greased, monster slips off; this
793            protection might fail (33% chance) when the armor is cursed */
794         if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) &&
795                 (!obj->cursed || rn2(3))) {
796             pline("%s %s your %s %s!",
797                   Monnam(mtmp),
798                   (mattk->adtyp == AD_WRAP) ?
799                         "slips off of" : "grabs you, but cannot hold onto",
800                   obj->greased ? "greased" : "slippery",
801                   /* avoid "slippery slippery cloak"
802                      for undiscovered oilskin cloak */
803                   (obj->greased || objects[obj->otyp].oc_name_known) ?
804                         xname(obj) : cloak_simple_name(obj));
805
806             if (obj->greased && !rn2(2)) {
807                 pline_The("grease wears off.");
808                 obj->greased = 0;
809                 update_inventory();
810             }
811             return TRUE;
812         }
813         return FALSE;
814 }
815
816 /* armor that sufficiently covers the body might be able to block magic */
817 int
818 magic_negation(mon)
819 struct monst *mon;
820 {
821         struct obj *armor;
822         int armpro = 0;
823
824         armor = (mon == &youmonst) ? uarm : which_armor(mon, W_ARM);
825         if (armor && armpro < objects[armor->otyp].a_can)
826             armpro = objects[armor->otyp].a_can;
827         armor = (mon == &youmonst) ? uarmc : which_armor(mon, W_ARMC);
828         if (armor && armpro < objects[armor->otyp].a_can)
829             armpro = objects[armor->otyp].a_can;
830         armor = (mon == &youmonst) ? uarmh : which_armor(mon, W_ARMH);
831         if (armor && armpro < objects[armor->otyp].a_can)
832             armpro = objects[armor->otyp].a_can;
833
834         /* armor types for shirt, gloves, shoes, and shield don't currently
835            provide any magic cancellation but we might as well be complete */
836 #ifdef TOURIST
837         armor = (mon == &youmonst) ? uarmu : which_armor(mon, W_ARMU);
838         if (armor && armpro < objects[armor->otyp].a_can)
839             armpro = objects[armor->otyp].a_can;
840 #endif
841         armor = (mon == &youmonst) ? uarmg : which_armor(mon, W_ARMG);
842         if (armor && armpro < objects[armor->otyp].a_can)
843             armpro = objects[armor->otyp].a_can;
844         armor = (mon == &youmonst) ? uarmf : which_armor(mon, W_ARMF);
845         if (armor && armpro < objects[armor->otyp].a_can)
846             armpro = objects[armor->otyp].a_can;
847         armor = (mon == &youmonst) ? uarms : which_armor(mon, W_ARMS);
848         if (armor && armpro < objects[armor->otyp].a_can)
849             armpro = objects[armor->otyp].a_can;
850
851 #ifdef STEED
852         /* this one is really a stretch... */
853         armor = (mon == &youmonst) ? 0 : which_armor(mon, W_SADDLE);
854         if (armor && armpro < objects[armor->otyp].a_can)
855             armpro = objects[armor->otyp].a_can;
856 #endif
857
858         return armpro;
859 }
860
861 /*
862  * hitmu: monster hits you
863  *        returns 2 if monster dies (e.g. "yellow light"), 1 otherwise
864  *        3 if the monster lives but teleported/paralyzed, so it can't keep
865  *             attacking you
866  */
867 STATIC_OVL int
868 hitmu(mtmp, mattk)
869         register struct monst *mtmp;
870         register struct attack  *mattk;
871 {
872         register struct permonst *mdat = mtmp->data;
873         register int uncancelled, ptmp;
874         int dmg, armpro, permdmg;
875         char     buf[BUFSZ];
876         struct permonst *olduasmon = youmonst.data;
877         int res;
878
879         if (!canspotmon(mtmp))
880             map_invisible(mtmp->mx, mtmp->my);
881
882 /*      If the monster is undetected & hits you, you should know where
883  *      the attack came from.
884  */
885         if(mtmp->mundetected && (hides_under(mdat) || mdat->mlet == S_EEL)) {
886             mtmp->mundetected = 0;
887             if (!(Blind ? Blind_telepat : Unblind_telepat)) {
888                 struct obj *obj;
889                 const char *what;
890
891                 if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) {
892                     if (Blind && !obj->dknown)
893                         what = something;
894                     else if (is_pool(mtmp->mx, mtmp->my) && !Underwater)
895                         what = "the water";
896                     else
897                         what = doname(obj);
898
899                     pline("%s was hidden under %s!", Amonnam(mtmp), what);
900                 }
901                 newsym(mtmp->mx, mtmp->my);
902             }
903         }
904
905 /*      First determine the base damage done */
906         dmg = d((int)mattk->damn, (int)mattk->damd);
907         if(is_undead(mdat) && midnight())
908                 dmg += d((int)mattk->damn, (int)mattk->damd); /* extra damage */
909
910 /*      Next a cancellation factor      */
911 /*      Use uncancelled when the cancellation factor takes into account certain
912  *      armor's special magic protection.  Otherwise just use !mtmp->mcan.
913  */
914         armpro = magic_negation(&youmonst);
915         uncancelled = !mtmp->mcan && ((rn2(3) >= armpro) || !rn2(50));
916
917         permdmg = 0;
918 /*      Now, adjust damages via resistances or specific attacks */
919         switch(mattk->adtyp) {
920             case AD_PHYS:
921                 if (mattk->aatyp == AT_HUGS && !sticks(youmonst.data)) {
922                     if(!u.ustuck && rn2(2)) {
923                         if (u_slip_free(mtmp, mattk)) {
924                             dmg = 0;
925                         } else {
926                             u.ustuck = mtmp;
927                             pline("%s grabs you!", Monnam(mtmp));
928                         }
929                     } else if(u.ustuck == mtmp) {
930                         exercise(A_STR, FALSE);
931                         You("are being %s.",
932                               (mtmp->data == &mons[PM_ROPE_GOLEM])
933                               ? "choked" : "crushed");
934                     }
935                 } else {                          /* hand to hand weapon */
936                     if(mattk->aatyp == AT_WEAP && otmp) {
937                         if (otmp->otyp == CORPSE
938                                 && touch_petrifies(&mons[otmp->corpsenm])) {
939                             dmg = 1;
940                             pline("%s hits you with the %s corpse.",
941                                 Monnam(mtmp), mons[otmp->corpsenm].mname);
942                             if (!Stoned)
943                                 goto do_stone;
944                         }
945                         dmg += dmgval(otmp, &youmonst);
946                         if (dmg <= 0) dmg = 1;
947                         if (!(otmp->oartifact &&
948                                 artifact_hit(mtmp, &youmonst, otmp, &dmg,dieroll)))
949                              hitmsg(mtmp, mattk);
950                         if (!dmg) break;
951                         if (u.mh > 1 && u.mh > ((u.uac>0) ? dmg : dmg+u.uac) &&
952                                    objects[otmp->otyp].oc_material == IRON &&
953                                         (u.umonnum==PM_BLACK_PUDDING
954                                         || u.umonnum==PM_BROWN_PUDDING)) {
955                             /* This redundancy necessary because you have to
956                              * take the damage _before_ being cloned.
957                              */
958                             if (u.uac < 0) dmg += u.uac;
959                             if (dmg < 1) dmg = 1;
960                             if (dmg > 1) exercise(A_STR, FALSE);
961                             u.mh -= dmg;
962                             flags.botl = 1;
963                             dmg = 0;
964                             if(cloneu())
965                             You("divide as %s hits you!",mon_nam(mtmp));
966                         }
967                         urustm(mtmp, otmp);
968                     } else if (mattk->aatyp != AT_TUCH || dmg != 0 ||
969                                 mtmp != u.ustuck)
970                         hitmsg(mtmp, mattk);
971                 }
972                 break;
973             case AD_DISE:
974                 hitmsg(mtmp, mattk);
975                 if (!diseasemu(mdat)) dmg = 0;
976                 break;
977             case AD_FIRE:
978                 hitmsg(mtmp, mattk);
979                 if (uncancelled) {
980                     pline("You're %s!", on_fire(youmonst.data, mattk));
981                     if (youmonst.data == &mons[PM_STRAW_GOLEM] ||
982                         youmonst.data == &mons[PM_PAPER_GOLEM]) {
983                             You("roast!");
984                             /* KMH -- this is okay with unchanging */
985                             rehumanize();
986                             break;
987                     } else if (Fire_resistance) {
988                         pline_The("fire doesn't feel hot!");
989                         dmg = 0;
990                     }
991                     if((int) mtmp->m_lev > rn2(20))
992                         destroy_item(SCROLL_CLASS, AD_FIRE);
993                     if((int) mtmp->m_lev > rn2(20))
994                         destroy_item(POTION_CLASS, AD_FIRE);
995                     if((int) mtmp->m_lev > rn2(25))
996                         destroy_item(SPBOOK_CLASS, AD_FIRE);
997                     burn_away_slime();
998                 } else dmg = 0;
999                 break;
1000             case AD_COLD:
1001                 hitmsg(mtmp, mattk);
1002                 if (uncancelled) {
1003                     pline("You're covered in frost!");
1004                     if (Cold_resistance) {
1005                         pline_The("frost doesn't seem cold!");
1006                         dmg = 0;
1007                     }
1008                     if((int) mtmp->m_lev > rn2(20))
1009                         destroy_item(POTION_CLASS, AD_COLD);
1010                 } else dmg = 0;
1011                 break;
1012             case AD_ELEC:
1013                 hitmsg(mtmp, mattk);
1014                 if (uncancelled) {
1015                     You("get zapped!");
1016                     if (Shock_resistance) {
1017                         pline_The("zap doesn't shock you!");
1018                         dmg = 0;
1019                     }
1020                     if((int) mtmp->m_lev > rn2(20))
1021                         destroy_item(WAND_CLASS, AD_ELEC);
1022                     if((int) mtmp->m_lev > rn2(20))
1023                         destroy_item(RING_CLASS, AD_ELEC);
1024                 } else dmg = 0;
1025                 break;
1026             case AD_SLEE:
1027                 hitmsg(mtmp, mattk);
1028                 if (uncancelled && multi >= 0 && !rn2(5)) {
1029                     if (Sleep_resistance) break;
1030                     fall_asleep(-rnd(10), TRUE);
1031                     if (Blind) You("are put to sleep!");
1032                     else You("are put to sleep by %s!", mon_nam(mtmp));
1033                 }
1034                 break;
1035             case AD_BLND:
1036                 if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) {
1037                     if (!Blind) pline("%s blinds you!", Monnam(mtmp));
1038                     make_blinded(Blinded+(long)dmg,FALSE);
1039                     if (!Blind) Your(vision_clears);
1040                 }
1041                 dmg = 0;
1042                 break;
1043             case AD_DRST:
1044                 ptmp = A_STR;
1045                 goto dopois;
1046             case AD_DRDX:
1047                 ptmp = A_DEX;
1048                 goto dopois;
1049             case AD_DRCO:
1050                 ptmp = A_CON;
1051 dopois:
1052                 hitmsg(mtmp, mattk);
1053                 if (uncancelled && !rn2(8)) {
1054                     Sprintf(buf, "%s %s",
1055                             s_suffix(Monnam(mtmp)), mpoisons_subj(mtmp, mattk));
1056                     poisoned(buf, ptmp, mdat->mname, 30);
1057                 }
1058                 break;
1059             case AD_DRIN:
1060                 hitmsg(mtmp, mattk);
1061                 if (defends(AD_DRIN, uwep) || !has_head(youmonst.data)) {
1062                     You("don't seem harmed.");
1063                     /* Not clear what to do for green slimes */
1064                     break;
1065                 }
1066                 if (u_slip_free(mtmp,mattk)) break;
1067
1068                 if (uarmh && rn2(8)) {
1069                     /* not body_part(HEAD) */
1070                     Your("helmet blocks the attack to your head.");
1071                     break;
1072                 }
1073                 if (Half_physical_damage) dmg = (dmg+1) / 2;
1074                 mdamageu(mtmp, dmg);
1075
1076                 if (!uarmh || uarmh->otyp != DUNCE_CAP) {
1077                     Your("brain is eaten!");
1078                     /* No such thing as mindless players... */
1079                     if (ABASE(A_INT) <= ATTRMIN(A_INT)) {
1080                         int lifesaved = 0;
1081                         struct obj *wore_amulet = uamul;
1082
1083                         while(1) {
1084                             /* avoid looping on "die(y/n)?" */
1085                             if (lifesaved && (discover || wizard)) {
1086                                 if (wore_amulet && !uamul) {
1087                                     /* used up AMULET_OF_LIFE_SAVING; still
1088                                        subject to dying from brainlessness */
1089                                     wore_amulet = 0;
1090                                 } else {
1091                                     /* explicitly chose not to die;
1092                                        arbitrarily boost intelligence */
1093                                     ABASE(A_INT) = ATTRMIN(A_INT) + 2;
1094                                     You_feel("like a scarecrow.");
1095                                     break;
1096                                 }
1097                             }
1098
1099                             if (lifesaved)
1100                                 pline("Unfortunately your brain is still gone.");
1101                             else
1102                                 Your("last thought fades away.");
1103                             killer = "brainlessness";
1104                             killer_format = KILLED_BY;
1105                             done(DIED);
1106                             lifesaved++;
1107                         }
1108                     }
1109                 }
1110                 /* adjattrib gives dunce cap message when appropriate */
1111                 (void) adjattrib(A_INT, -rnd(2), FALSE);
1112                 forget_levels(25);      /* lose memory of 25% of levels */
1113                 forget_objects(25);     /* lose memory of 25% of objects */
1114                 exercise(A_WIS, FALSE);
1115                 break;
1116             case AD_PLYS:
1117                 hitmsg(mtmp, mattk);
1118                 if (uncancelled && multi >= 0 && !rn2(3)) {
1119                     if (Free_action) {
1120                         You("momentarily stiffen.");            
1121                     } else {
1122                         if (Blind) You("are frozen!");
1123                         else You("are frozen by %s!", mon_nam(mtmp));
1124                         nomovemsg = 0;  /* default: "you can move again" */
1125                         nomul(-rnd(10));
1126                         exercise(A_DEX, FALSE);
1127                     }
1128                 }
1129                 break;
1130             case AD_DRLI:
1131                 hitmsg(mtmp, mattk);
1132                 if (uncancelled && !rn2(3) && !Drain_resistance) {
1133                     losexp("life drainage");
1134                 }
1135                 break;
1136             case AD_LEGS:
1137                 { register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
1138                   const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left";
1139
1140                 /* This case is too obvious to ignore, but Nethack is not in
1141                  * general very good at considering height--most short monsters
1142                  * still _can_ attack you when you're flying or mounted.
1143                  * [FIXME: why can't a flying attacker overcome this?]
1144                  */
1145                   if (
1146 #ifdef STEED
1147                         u.usteed ||
1148 #endif
1149                                     Levitation || Flying) {
1150                     pline("%s tries to reach your %s %s!", Monnam(mtmp),
1151                           sidestr, body_part(LEG));
1152                     dmg = 0;
1153                   } else if (mtmp->mcan) {
1154                     pline("%s nuzzles against your %s %s!", Monnam(mtmp),
1155                           sidestr, body_part(LEG));
1156                     dmg = 0;
1157                   } else {
1158                     if (uarmf) {
1159                         if (rn2(2) && (uarmf->otyp == LOW_BOOTS ||
1160                                              uarmf->otyp == IRON_SHOES))
1161                             pline("%s pricks the exposed part of your %s %s!",
1162                                 Monnam(mtmp), sidestr, body_part(LEG));
1163                         else if (!rn2(5))
1164                             pline("%s pricks through your %s boot!",
1165                                 Monnam(mtmp), sidestr);
1166                         else {
1167                             pline("%s scratches your %s boot!", Monnam(mtmp),
1168                                 sidestr);
1169                             dmg = 0;
1170                             break;
1171                         }
1172                     } else pline("%s pricks your %s %s!", Monnam(mtmp),
1173                           sidestr, body_part(LEG));
1174                     set_wounded_legs(side, rnd(60-ACURR(A_DEX)));
1175                     exercise(A_STR, FALSE);
1176                     exercise(A_DEX, FALSE);
1177                   }
1178                   break;
1179                 }
1180             case AD_STON:       /* cockatrice */
1181                 hitmsg(mtmp, mattk);
1182                 if(!rn2(3)) {
1183                     if (mtmp->mcan) {
1184                         if (flags.soundok)
1185                             You_hear("a cough from %s!", mon_nam(mtmp));
1186                     } else {
1187                         if (flags.soundok)
1188                             You_hear("%s hissing!", s_suffix(mon_nam(mtmp)));
1189                         if(!rn2(10) ||
1190                             (flags.moonphase == NEW_MOON && !have_lizard())) {
1191  do_stone:
1192                             if (!Stoned && !Stone_resistance
1193                                     && !(poly_when_stoned(youmonst.data) &&
1194                                         polymon(PM_STONE_GOLEM))) {
1195                                 Stoned = 5;
1196                                 delayed_killer = mtmp->data->mname;
1197                                 if (mtmp->data->geno & G_UNIQ) {
1198                                     if (!type_is_pname(mtmp->data)) {
1199                                         static char kbuf[BUFSZ];
1200
1201                                         /* "the" buffer may be reallocated */
1202                                         Strcpy(kbuf, the(delayed_killer));
1203                                         delayed_killer = kbuf;
1204                                     }
1205                                     killer_format = KILLED_BY;
1206                                 } else killer_format = KILLED_BY_AN;
1207                                 return(1);
1208                                 /* You("turn to stone..."); */
1209                                 /* done_in_by(mtmp); */
1210                             }
1211                         }
1212                     }
1213                 }
1214                 break;
1215             case AD_STCK:
1216                 hitmsg(mtmp, mattk);
1217                 if (uncancelled && !u.ustuck && !sticks(youmonst.data))
1218                         u.ustuck = mtmp;
1219                 break;
1220             case AD_WRAP:
1221                 if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(youmonst.data)) {
1222                     if (!u.ustuck && !rn2(10)) {
1223                         if (u_slip_free(mtmp, mattk)) {
1224                             dmg = 0;
1225                         } else {
1226                             pline("%s swings itself around you!",
1227                                   Monnam(mtmp));
1228                             u.ustuck = mtmp;
1229                         }
1230                     } else if(u.ustuck == mtmp) {
1231                         if (is_pool(mtmp->mx,mtmp->my) && !Swimming
1232                             && !Amphibious) {
1233                             boolean moat =
1234                                 (levl[mtmp->mx][mtmp->my].typ != POOL) &&
1235                                 (levl[mtmp->mx][mtmp->my].typ != WATER) &&
1236                                 !Is_medusa_level(&u.uz) &&
1237                                 !Is_waterlevel(&u.uz);
1238
1239                             pline("%s drowns you...", Monnam(mtmp));
1240                             killer_format = KILLED_BY_AN;
1241                             Sprintf(buf, "%s by %s",
1242                                     moat ? "moat" : "pool of water",
1243                                     an(mtmp->data->mname));
1244                             killer = buf;
1245                             done(DROWNING);
1246                         } else if(mattk->aatyp == AT_HUGS)
1247                             You("are being crushed.");
1248                     } else {
1249                         dmg = 0;
1250                         if(flags.verbose)
1251                             pline("%s brushes against your %s.", Monnam(mtmp),
1252                                    body_part(LEG));
1253                     }
1254                 } else dmg = 0;
1255                 break;
1256             case AD_WERE:
1257                 hitmsg(mtmp, mattk);
1258                 if (uncancelled && !rn2(4) && u.ulycn == NON_PM &&
1259                         !Protection_from_shape_changers &&
1260                         !defends(AD_WERE,uwep)) {
1261                     You_feel("feverish.");
1262                     exercise(A_CON, FALSE);
1263                     u.ulycn = monsndx(mdat);
1264                 }
1265                 break;
1266             case AD_SGLD:
1267                 hitmsg(mtmp, mattk);
1268                 if (youmonst.data->mlet == mdat->mlet) break;
1269                 if(!mtmp->mcan) stealgold(mtmp);
1270                 break;
1271
1272             case AD_SITM:       /* for now these are the same */
1273             case AD_SEDU:
1274                 if (is_animal(mtmp->data)) {
1275                         hitmsg(mtmp, mattk);
1276                         if (mtmp->mcan) break;
1277                         /* Continue below */
1278                 } else if (dmgtype(youmonst.data, AD_SEDU)
1279 #ifdef SEDUCE
1280                         || dmgtype(youmonst.data, AD_SSEX)
1281 #endif
1282                                                 ) {
1283                         pline("%s %s.", Monnam(mtmp), mtmp->minvent ?
1284                     "brags about the goods some dungeon explorer provided" :
1285                     "makes some remarks about how difficult theft is lately");
1286                         if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
1287                         return 3;
1288                 } else if (mtmp->mcan) {
1289                     if (!Blind) {
1290                         pline("%s tries to %s you, but you seem %s.",
1291                             Adjmonnam(mtmp, "plain"),
1292                             flags.female ? "charm" : "seduce",
1293                             flags.female ? "unaffected" : "uninterested");
1294                     }
1295                     if(rn2(3)) {
1296                         if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
1297                         return 3;
1298                     }
1299                     break;
1300                 }
1301                 buf[0] = '\0';
1302                 switch (steal(mtmp, buf)) {
1303                   case -1:
1304                         return 2;
1305                   case 0:
1306                         break;
1307                   default:
1308                         if (!is_animal(mtmp->data) && !tele_restrict(mtmp))
1309                             (void) rloc(mtmp, FALSE);
1310                         if (is_animal(mtmp->data) && *buf) {
1311                             if (canseemon(mtmp))
1312                                 pline("%s tries to %s away with %s.",
1313                                       Monnam(mtmp),
1314                                       locomotion(mtmp->data, "run"),
1315                                       buf);
1316                         }
1317                         monflee(mtmp, 0, FALSE, FALSE);
1318                         return 3;
1319                 }
1320                 break;
1321 #ifdef SEDUCE
1322             case AD_SSEX:
1323                 if(could_seduce(mtmp, &youmonst, mattk) == 1
1324                         && !mtmp->mcan)
1325                     if (doseduce(mtmp))
1326                         return 3;
1327                 break;
1328 #endif
1329             case AD_SAMU:
1330                 hitmsg(mtmp, mattk);
1331                 /* when the Wiz hits, 1/20 steals the amulet */
1332                 if (u.uhave.amulet ||
1333                      u.uhave.bell || u.uhave.book || u.uhave.menorah
1334                      || u.uhave.questart) /* carrying the Quest Artifact */
1335                     if (!rn2(20)) stealamulet(mtmp);
1336                 break;
1337
1338             case AD_TLPT:
1339                 hitmsg(mtmp, mattk);
1340                 if (uncancelled) {
1341                     if(flags.verbose)
1342                         Your("position suddenly seems very uncertain!");
1343                     tele();
1344                 }
1345                 break;
1346             case AD_RUST:
1347                 hitmsg(mtmp, mattk);
1348                 if (mtmp->mcan) break;
1349                 if (u.umonnum == PM_IRON_GOLEM) {
1350                         You("rust!");
1351                         /* KMH -- this is okay with unchanging */
1352                         rehumanize();
1353                         break;
1354                 }
1355                 hurtarmor(AD_RUST);
1356                 break;
1357             case AD_CORR:
1358                 hitmsg(mtmp, mattk);
1359                 if (mtmp->mcan) break;
1360                 hurtarmor(AD_CORR);
1361                 break;
1362             case AD_DCAY:
1363                 hitmsg(mtmp, mattk);
1364                 if (mtmp->mcan) break;
1365                 if (u.umonnum == PM_WOOD_GOLEM ||
1366                     u.umonnum == PM_LEATHER_GOLEM) {
1367                         You("rot!");
1368                         /* KMH -- this is okay with unchanging */
1369                         rehumanize();
1370                         break;
1371                 }
1372                 hurtarmor(AD_DCAY);
1373                 break;
1374             case AD_HEAL:
1375                 /* a cancelled nurse is just an ordinary monster */
1376                 if (mtmp->mcan) {
1377                     hitmsg(mtmp, mattk);
1378                     break;
1379                 }
1380                 if(!uwep
1381 #ifdef TOURIST
1382                    && !uarmu
1383 #endif
1384                    && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf) {
1385                     boolean goaway = FALSE;
1386                     pline("%s hits!  (I hope you don't mind.)", Monnam(mtmp));
1387                     if (Upolyd) {
1388                         u.mh += rnd(7);
1389                         if (!rn2(7)) {
1390                             /* no upper limit necessary; effect is temporary */
1391                             u.mhmax++;
1392                             if (!rn2(13)) goaway = TRUE;
1393                         }
1394                         if (u.mh > u.mhmax) u.mh = u.mhmax;
1395                     } else {
1396                         u.uhp += rnd(7);
1397                         if (!rn2(7)) {
1398                             /* hard upper limit via nurse care: 25 * ulevel */
1399                             if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10))
1400                                 u.uhpmax++;
1401                             if (!rn2(13)) goaway = TRUE;
1402                         }
1403                         if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
1404                     }
1405                     if (!rn2(3)) exercise(A_STR, TRUE);
1406                     if (!rn2(3)) exercise(A_CON, TRUE);
1407                     if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1408                     flags.botl = 1;
1409                     if (goaway) {
1410                         mongone(mtmp);
1411                         return 2;
1412                     } else if (!rn2(33)) {
1413                         if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
1414                         monflee(mtmp, d(3, 6), TRUE, FALSE);
1415                         return 3;
1416                     }
1417                     dmg = 0;
1418                 } else {
1419                     if (Role_if(PM_HEALER)) {
1420                         if (flags.soundok && !(moves % 5))
1421                       verbalize("Doc, I can't help you unless you cooperate.");
1422                         dmg = 0;
1423                     } else hitmsg(mtmp, mattk);
1424                 }
1425                 break;
1426             case AD_CURS:
1427                 hitmsg(mtmp, mattk);
1428                 if(!night() && mdat == &mons[PM_GREMLIN]) break;
1429                 if(!mtmp->mcan && !rn2(10)) {
1430                     if (flags.soundok) {
1431                         if (Blind) You_hear("laughter.");
1432                         else       pline("%s chuckles.", Monnam(mtmp));
1433                     }
1434                     if (u.umonnum == PM_CLAY_GOLEM) {
1435                         pline("Some writing vanishes from your head!");
1436                         /* KMH -- this is okay with unchanging */
1437                         rehumanize();
1438                         break;
1439                     }
1440                     attrcurse();
1441                 }
1442                 break;
1443             case AD_STUN:
1444                 hitmsg(mtmp, mattk);
1445                 if(!mtmp->mcan && !rn2(4)) {
1446                     make_stunned(HStun + dmg, TRUE);
1447                     dmg /= 2;
1448                 }
1449                 break;
1450             case AD_ACID:
1451                 hitmsg(mtmp, mattk);
1452                 if (!mtmp->mcan && !rn2(3))
1453                     if (Acid_resistance) {
1454                         pline("You're covered in acid, but it seems harmless.");
1455                         dmg = 0;
1456                     } else {
1457                         pline("You're covered in acid!  It burns!");
1458                         exercise(A_STR, FALSE);
1459                     }
1460                 else            dmg = 0;
1461                 break;
1462             case AD_SLOW:
1463                 hitmsg(mtmp, mattk);
1464                 if (uncancelled && HFast &&
1465                                         !defends(AD_SLOW, uwep) && !rn2(4))
1466                     u_slow_down();
1467                 break;
1468             case AD_DREN:
1469                 hitmsg(mtmp, mattk);
1470                 if (uncancelled && !rn2(4))
1471                     drain_en(dmg);
1472                 dmg = 0;
1473                 break;
1474             case AD_CONF:
1475                 hitmsg(mtmp, mattk);
1476                 if(!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) {
1477                     mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6));
1478                     if(Confusion)
1479                          You("are getting even more confused.");
1480                     else You("are getting confused.");
1481                     make_confused(HConfusion + dmg, FALSE);
1482                 }
1483                 dmg = 0;
1484                 break;
1485             case AD_DETH:
1486                 pline("%s reaches out with its deadly touch.", Monnam(mtmp));
1487                 if (is_undead(youmonst.data)) {
1488                     /* Still does normal damage */
1489                     pline("Was that the touch of death?");
1490                     break;
1491                 }
1492                 switch (rn2(20)) {
1493                 case 19: case 18: case 17:
1494                     if (!Antimagic) {
1495                         killer_format = KILLED_BY_AN;
1496                         killer = "touch of death";
1497                         done(DIED);
1498                         dmg = 0;
1499                         break;
1500                     } /* else FALLTHRU */
1501                 default: /* case 16: ... case 5: */
1502                     You_feel("your life force draining away...");
1503                     permdmg = 1;        /* actual damage done below */
1504                     break;
1505                 case 4: case 3: case 2: case 1: case 0:
1506                     if (Antimagic) shieldeff(u.ux, u.uy);
1507                     pline("Lucky for you, it didn't work!");
1508                     dmg = 0;
1509                     break;
1510                 }
1511                 break;
1512             case AD_PEST:
1513                 pline("%s reaches out, and you feel fever and chills.",
1514                         Monnam(mtmp));
1515                 (void) diseasemu(mdat); /* plus the normal damage */
1516                 break;
1517             case AD_FAMN:
1518                 pline("%s reaches out, and your body shrivels.",
1519                         Monnam(mtmp));
1520                 exercise(A_CON, FALSE);
1521                 if (!is_fainted()) morehungry(rn1(40,40));
1522                 /* plus the normal damage */
1523                 break;
1524             case AD_SLIM:    
1525                 hitmsg(mtmp, mattk);
1526                 if (!uncancelled) break;
1527                 if (flaming(youmonst.data)) {
1528                     pline_The("slime burns away!");
1529                     dmg = 0;
1530                 } else if (Unchanging ||
1531                                 youmonst.data == &mons[PM_GREEN_SLIME]) {
1532                     You("are unaffected.");
1533                     dmg = 0;
1534                 } else if (!Slimed) {
1535                     You("don't feel very well.");
1536                     Slimed = 10L;
1537                     flags.botl = 1;
1538                     killer_format = KILLED_BY_AN;
1539                     delayed_killer = mtmp->data->mname;
1540                 } else
1541                     pline("Yuck!");
1542                 break;
1543             case AD_ENCH:       /* KMH -- remove enchantment (disenchanter) */
1544                 hitmsg(mtmp, mattk);
1545                 /* uncancelled is sufficient enough; please
1546                    don't make this attack less frequent */
1547                 if (uncancelled) {
1548                     struct obj *obj = some_armor(&youmonst);
1549
1550                     if (drain_item(obj)) {
1551                         Your("%s less effective.", aobjnam(obj, "seem"));
1552                     }
1553                 }
1554                 break;
1555             default:    dmg = 0;
1556                         break;
1557         }
1558         if(u.uhp < 1) done_in_by(mtmp);
1559
1560 /*      Negative armor class reduces damage done instead of fully protecting
1561  *      against hits.
1562  */
1563         if (dmg && u.uac < 0) {
1564                 dmg -= rnd(-u.uac);
1565                 if (dmg < 1) dmg = 1;
1566         }
1567
1568         if(dmg) {
1569             if (Half_physical_damage
1570                                         /* Mitre of Holiness */
1571                 || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh) &&
1572                     (is_undead(mtmp->data) || is_demon(mtmp->data))))
1573                 dmg = (dmg+1) / 2;
1574
1575             if (permdmg) {      /* Death's life force drain */
1576                 int lowerlimit, *hpmax_p;
1577                 /*
1578                  * Apply some of the damage to permanent hit points:
1579                  *      polymorphed         100% against poly'd hpmax
1580                  *      hpmax > 25*lvl      100% against normal hpmax
1581                  *      hpmax > 10*lvl  50..100%
1582                  *      hpmax >  5*lvl  25..75%
1583                  *      otherwise        0..50%
1584                  * Never reduces hpmax below 1 hit point per level.
1585                  */
1586                 permdmg = rn2(dmg / 2 + 1);
1587                 if (Upolyd || u.uhpmax > 25 * u.ulevel) permdmg = dmg;
1588                 else if (u.uhpmax > 10 * u.ulevel) permdmg += dmg / 2;
1589                 else if (u.uhpmax > 5 * u.ulevel) permdmg += dmg / 4;
1590
1591                 if (Upolyd) {
1592                     hpmax_p = &u.mhmax;
1593                     /* [can't use youmonst.m_lev] */
1594                     lowerlimit = min((int)youmonst.data->mlevel, u.ulevel);
1595                 } else {
1596                     hpmax_p = &u.uhpmax;
1597                     lowerlimit = u.ulevel;
1598                 }
1599                 if (*hpmax_p - permdmg > lowerlimit)
1600                     *hpmax_p -= permdmg;
1601                 else if (*hpmax_p > lowerlimit)
1602                     *hpmax_p = lowerlimit;
1603                 else    /* unlikely... */
1604                     ;   /* already at or below minimum threshold; do nothing */
1605                 flags.botl = 1;
1606             }
1607
1608             mdamageu(mtmp, dmg);
1609         }
1610
1611         if (dmg)
1612             res = passiveum(olduasmon, mtmp, mattk);
1613         else
1614             res = 1;
1615         stop_occupation();
1616         return res;
1617 }
1618
1619 #endif /* OVL1 */
1620 #ifdef OVLB
1621
1622 STATIC_OVL int
1623 gulpmu(mtmp, mattk)     /* monster swallows you, or damage if u.uswallow */
1624         register struct monst *mtmp;
1625         register struct attack  *mattk;
1626 {
1627         struct trap *t = t_at(u.ux, u.uy);
1628         int     tmp = d((int)mattk->damn, (int)mattk->damd);
1629         int     tim_tmp;
1630         register struct obj *otmp2;
1631         int     i;
1632
1633         if (!u.uswallow) {      /* swallows you */
1634                 if (youmonst.data->msize >= MZ_HUGE) return(0);
1635                 if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT))) &&
1636                     sobj_at(BOULDER, u.ux, u.uy))
1637                         return(0);
1638
1639                 if (Punished) unplacebc();      /* ball&chain go away */
1640                 remove_monster(mtmp->mx, mtmp->my);
1641                 mtmp->mtrapped = 0;             /* no longer on old trap */
1642                 place_monster(mtmp, u.ux, u.uy);
1643                 u.ustuck = mtmp;
1644                 newsym(mtmp->mx,mtmp->my);
1645 #ifdef STEED
1646                 if (is_animal(mtmp->data) && u.usteed) {
1647                         char buf[BUFSZ];
1648                         /* Too many quirks presently if hero and steed
1649                          * are swallowed. Pretend purple worms don't
1650                          * like horses for now :-)
1651                          */
1652                         Strcpy(buf, mon_nam(u.usteed));
1653                         pline ("%s lunges forward and plucks you off %s!",
1654                                 Monnam(mtmp), buf);
1655                         dismount_steed(DISMOUNT_ENGULFED);
1656                 } else
1657 #endif
1658                 pline("%s engulfs you!", Monnam(mtmp));
1659                 stop_occupation();
1660                 reset_occupations();    /* behave as if you had moved */
1661
1662                 if (u.utrap) {
1663                         You("are released from the %s!",
1664                                 u.utraptype==TT_WEB ? "web" : "trap");
1665                         u.utrap = 0;
1666                 }
1667
1668                 i = number_leashed();
1669                 if (i > 0) {
1670                     const char *s = (i > 1) ? "leashes" : "leash";
1671                     pline_The("%s %s loose.", s, vtense(s, "snap"));
1672                     unleash_all();
1673                 }
1674
1675                 if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
1676                         minstapetrify(mtmp, TRUE);
1677                         if (mtmp->mhp > 0) return 0;
1678                         else return 2;
1679                 }
1680
1681                 display_nhwindow(WIN_MESSAGE, FALSE);
1682                 vision_recalc(2);       /* hero can't see anything */
1683                 u.uswallow = 1;
1684                 /* u.uswldtim always set > 1 */
1685                 tim_tmp = 25 - (int)mtmp->m_lev;
1686                 if (tim_tmp > 0) tim_tmp = rnd(tim_tmp) / 2;
1687                 else if (tim_tmp < 0) tim_tmp = -(rnd(-tim_tmp) / 2);
1688                 tim_tmp += -u.uac + 10;
1689                 u.uswldtim = (unsigned)((tim_tmp < 2) ? 2 : tim_tmp);
1690                 swallowed(1);
1691                 for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
1692                     (void) snuff_lit(otmp2);
1693         }
1694
1695         if (mtmp != u.ustuck) return(0);
1696         if (u.uswldtim > 0) u.uswldtim -= 1;
1697
1698         switch(mattk->adtyp) {
1699
1700                 case AD_DGST:
1701                     if (Slow_digestion) {
1702                         /* Messages are handled below */
1703                         u.uswldtim = 0;
1704                         tmp = 0;
1705                     } else if (u.uswldtim == 0) {
1706                         pline("%s totally digests you!", Monnam(mtmp));
1707                         tmp = u.uhp;
1708                         if (Half_physical_damage) tmp *= 2; /* sorry */
1709                     } else {
1710                         pline("%s%s digests you!", Monnam(mtmp),
1711                               (u.uswldtim == 2) ? " thoroughly" :
1712                               (u.uswldtim == 1) ? " utterly" : "");
1713                         exercise(A_STR, FALSE);
1714                     }
1715                     break;
1716                 case AD_PHYS:
1717                     if (mtmp->data == &mons[PM_FOG_CLOUD]) {
1718                         You("are laden with moisture and %s",
1719                             flaming(youmonst.data) ? "are smoldering out!" :
1720                             Breathless ? "find it mildly uncomfortable." :
1721                             amphibious(youmonst.data) ? "feel comforted." :
1722                             "can barely breathe!");
1723                         /* NB: Amphibious includes Breathless */
1724                         if (Amphibious && !flaming(youmonst.data)) tmp = 0;
1725                     } else {
1726                         You("are pummeled with debris!");
1727                         exercise(A_STR, FALSE);
1728                     }
1729                     break;
1730                 case AD_ACID:
1731                     if (Acid_resistance) {
1732                         You("are covered with a seemingly harmless goo.");
1733                         tmp = 0;
1734                     } else {
1735                       if (Hallucination) pline("Ouch!  You've been slimed!");
1736                       else You("are covered in slime!  It burns!");
1737                       exercise(A_STR, FALSE);
1738                     }
1739                     break;
1740                 case AD_BLND:
1741                     if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) {
1742                         if(!Blind) {
1743                             You_cant("see in here!");
1744                             make_blinded((long)tmp,FALSE);
1745                             if (!Blind) Your(vision_clears);
1746                         } else
1747                             /* keep him blind until disgorged */
1748                             make_blinded(Blinded+1,FALSE);
1749                     }
1750                     tmp = 0;
1751                     break;
1752                 case AD_ELEC:
1753                     if(!mtmp->mcan && rn2(2)) {
1754                         pline_The("air around you crackles with electricity.");
1755                         if (Shock_resistance) {
1756                                 shieldeff(u.ux, u.uy);
1757                                 You("seem unhurt.");
1758                                 ugolemeffects(AD_ELEC,tmp);
1759                                 tmp = 0;
1760                         }
1761                     } else tmp = 0;
1762                     break;
1763                 case AD_COLD:
1764                     if(!mtmp->mcan && rn2(2)) {
1765                         if (Cold_resistance) {
1766                                 shieldeff(u.ux, u.uy);
1767                                 You_feel("mildly chilly.");
1768                                 ugolemeffects(AD_COLD,tmp);
1769                                 tmp = 0;
1770                         } else You("are freezing to death!");
1771                     } else tmp = 0;
1772                     break;
1773                 case AD_FIRE:
1774                     if(!mtmp->mcan && rn2(2)) {
1775                         if (Fire_resistance) {
1776                                 shieldeff(u.ux, u.uy);
1777                                 You_feel("mildly hot.");
1778                                 ugolemeffects(AD_FIRE,tmp);
1779                                 tmp = 0;
1780                         } else You("are burning to a crisp!");
1781                         burn_away_slime();
1782                     } else tmp = 0;
1783                     break;
1784                 case AD_DISE:
1785                     if (!diseasemu(mtmp->data)) tmp = 0;
1786                     break;
1787                 default:
1788                     tmp = 0;
1789                     break;
1790         }
1791
1792         if (Half_physical_damage) tmp = (tmp+1) / 2;
1793
1794         mdamageu(mtmp, tmp);
1795         if (tmp) stop_occupation();
1796
1797         if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
1798             pline("%s very hurriedly %s you!", Monnam(mtmp),
1799                   is_animal(mtmp->data)? "regurgitates" : "expels");
1800             expels(mtmp, mtmp->data, FALSE);
1801         } else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) {
1802             You("get %s!", is_animal(mtmp->data)? "regurgitated" : "expelled");
1803             if (flags.verbose && (is_animal(mtmp->data) ||
1804                     (dmgtype(mtmp->data, AD_DGST) && Slow_digestion)))
1805                 pline("Obviously %s doesn't like your taste.", mon_nam(mtmp));
1806             expels(mtmp, mtmp->data, FALSE);
1807         }
1808         return(1);
1809 }
1810
1811 STATIC_OVL int
1812 explmu(mtmp, mattk, ufound)     /* monster explodes in your face */
1813 register struct monst *mtmp;
1814 register struct attack  *mattk;
1815 boolean ufound;
1816 {
1817     if (mtmp->mcan) return(0);
1818
1819     if (!ufound)
1820         pline("%s explodes at a spot in %s!",
1821             canseemon(mtmp) ? Monnam(mtmp) : "It",
1822             levl[mtmp->mux][mtmp->muy].typ == WATER
1823                 ? "empty water" : "thin air");
1824     else {
1825         register int tmp = d((int)mattk->damn, (int)mattk->damd);
1826         register boolean not_affected = defends((int)mattk->adtyp, uwep);
1827
1828         hitmsg(mtmp, mattk);
1829
1830         switch (mattk->adtyp) {
1831             case AD_COLD:
1832                 not_affected |= Cold_resistance;
1833                 goto common;
1834             case AD_FIRE:
1835                 not_affected |= Fire_resistance;
1836                 goto common;
1837             case AD_ELEC:
1838                 not_affected |= Shock_resistance;
1839 common:
1840
1841                 if (!not_affected) {
1842                     if (ACURR(A_DEX) > rnd(20)) {
1843                         You("duck some of the blast.");
1844                         tmp = (tmp+1) / 2;
1845                     } else {
1846                         if (flags.verbose) You("get blasted!");
1847                     }
1848                     if (mattk->adtyp == AD_FIRE) burn_away_slime();
1849                     if (Half_physical_damage) tmp = (tmp+1) / 2;
1850                     mdamageu(mtmp, tmp);
1851                 }
1852                 break;
1853
1854             case AD_BLND:
1855                 not_affected = resists_blnd(&youmonst);
1856                 if (!not_affected) {
1857                     /* sometimes you're affected even if it's invisible */
1858                     if (mon_visible(mtmp) || (rnd(tmp /= 2) > u.ulevel)) {
1859                         You("are blinded by a blast of light!");
1860                         make_blinded((long)tmp, FALSE);
1861                         if (!Blind) Your(vision_clears);
1862                     } else if (flags.verbose)
1863                         You("get the impression it was not terribly bright.");
1864                 }
1865                 break;
1866
1867             case AD_HALU:
1868                 not_affected |= Blind ||
1869                         (u.umonnum == PM_BLACK_LIGHT ||
1870                          u.umonnum == PM_VIOLET_FUNGUS ||
1871                          dmgtype(youmonst.data, AD_STUN));
1872                 if (!not_affected) {
1873                     boolean chg;
1874                     if (!Hallucination)
1875                         You("are caught in a blast of kaleidoscopic light!");
1876                     chg = make_hallucinated(HHallucination + (long)tmp,FALSE,0L);
1877                     You("%s.", chg ? "are freaked out" : "seem unaffected");
1878                 }
1879                 break;
1880
1881             default:
1882                 break;
1883         }
1884         if (not_affected) {
1885             You("seem unaffected by it.");
1886             ugolemeffects((int)mattk->adtyp, tmp);
1887         }
1888     }
1889     mondead(mtmp);
1890     wake_nearto(mtmp->mx, mtmp->my, 7*7);
1891     if (mtmp->mhp > 0) return(0);
1892     return(2);  /* it dies */
1893 }
1894
1895 int
1896 gazemu(mtmp, mattk)     /* monster gazes at you */
1897         register struct monst *mtmp;
1898         register struct attack  *mattk;
1899 {
1900         switch(mattk->adtyp) {
1901             case AD_STON:
1902                 if (mtmp->mcan || !mtmp->mcansee) {
1903                     if (!canseemon(mtmp)) break;        /* silently */
1904                     pline("%s %s.", Monnam(mtmp),
1905                           (mtmp->data == &mons[PM_MEDUSA] && mtmp->mcan) ?
1906                                 "doesn't look all that ugly" :
1907                                 "gazes ineffectually");
1908                     break;
1909                 }
1910                 if (Reflecting && couldsee(mtmp->mx, mtmp->my) &&
1911                         mtmp->data == &mons[PM_MEDUSA]) {
1912                     /* hero has line of sight to Medusa and she's not blind */
1913                     boolean useeit = canseemon(mtmp);
1914
1915                     if (useeit)
1916                         (void) ureflects("%s gaze is reflected by your %s.",
1917                                          s_suffix(Monnam(mtmp)));
1918                     if (mon_reflects(mtmp, !useeit ? (char *)0 :
1919                                      "The gaze is reflected away by %s %s!"))
1920                         break;
1921                     if (!m_canseeu(mtmp)) { /* probably you're invisible */
1922                         if (useeit)
1923                             pline(
1924                       "%s doesn't seem to notice that %s gaze was reflected.",
1925                                   Monnam(mtmp), mhis(mtmp));
1926                         break;
1927                     }
1928                     if (useeit)
1929                         pline("%s is turned to stone!", Monnam(mtmp));
1930                     stoned = TRUE;
1931                     killed(mtmp);
1932
1933                     if (mtmp->mhp > 0) break;
1934                     return 2;
1935                 }
1936                 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
1937                     !Stone_resistance) {
1938                     You("meet %s gaze.", s_suffix(mon_nam(mtmp)));
1939                     stop_occupation();
1940                     if(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1941                         break;
1942                     You("turn to stone...");
1943                     killer_format = KILLED_BY;
1944                     killer = mtmp->data->mname;
1945                     done(STONING);
1946                 }
1947                 break;
1948             case AD_CONF:
1949                 if(!mtmp->mcan && canseemon(mtmp) &&
1950                    couldsee(mtmp->mx, mtmp->my) &&
1951                    mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
1952                     int conf = d(3,4);
1953
1954                     mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6));
1955                     if(!Confusion)
1956                         pline("%s gaze confuses you!",
1957                                           s_suffix(Monnam(mtmp)));
1958                     else
1959                         You("are getting more and more confused.");
1960                     make_confused(HConfusion + conf, FALSE);
1961                     stop_occupation();
1962                 }
1963                 break;
1964             case AD_STUN:
1965                 if(!mtmp->mcan && canseemon(mtmp) &&
1966                    couldsee(mtmp->mx, mtmp->my) &&
1967                    mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
1968                     int stun = d(2,6);
1969
1970                     mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6));
1971                     pline("%s stares piercingly at you!", Monnam(mtmp));
1972                     make_stunned(HStun + stun, TRUE);
1973                     stop_occupation();
1974                 }
1975                 break;
1976             case AD_BLND:
1977                 if (!mtmp->mcan && canseemon(mtmp) && !resists_blnd(&youmonst)
1978                         && distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) {
1979                     int blnd = d((int)mattk->damn, (int)mattk->damd);
1980
1981                     You("are blinded by %s radiance!",
1982                                       s_suffix(mon_nam(mtmp)));
1983                     make_blinded((long)blnd,FALSE);
1984                     stop_occupation();
1985                     /* not blind at this point implies you're wearing
1986                        the Eyes of the Overworld; make them block this
1987                        particular stun attack too */
1988                     if (!Blind) Your(vision_clears);
1989                     else make_stunned((long)d(1,3),TRUE);
1990                 }
1991                 break;
1992             case AD_FIRE:
1993                 if (!mtmp->mcan && canseemon(mtmp) &&
1994                         couldsee(mtmp->mx, mtmp->my) &&
1995                         mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
1996                     int dmg = d(2,6);
1997
1998                     pline("%s attacks you with a fiery gaze!", Monnam(mtmp));
1999                     stop_occupation();
2000                     if (Fire_resistance) {
2001                         pline_The("fire doesn't feel hot!");
2002                         dmg = 0;
2003                     }
2004                     burn_away_slime();
2005                     if ((int) mtmp->m_lev > rn2(20))
2006                         destroy_item(SCROLL_CLASS, AD_FIRE);
2007                     if ((int) mtmp->m_lev > rn2(20))
2008                         destroy_item(POTION_CLASS, AD_FIRE);
2009                     if ((int) mtmp->m_lev > rn2(25))
2010                         destroy_item(SPBOOK_CLASS, AD_FIRE);
2011                     if (dmg) mdamageu(mtmp, dmg);
2012                 }
2013                 break;
2014 #ifdef PM_BEHOLDER /* work in progress */
2015             case AD_SLEE:
2016                 if(!mtmp->mcan && canseemon(mtmp) &&
2017                    couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee &&
2018                    multi >= 0 && !rn2(5) && !Sleep_resistance) {
2019
2020                     fall_asleep(-rnd(10), TRUE);
2021                     pline("%s gaze makes you very sleepy...",
2022                           s_suffix(Monnam(mtmp)));
2023                 }
2024                 break;
2025             case AD_SLOW:
2026                 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee &&
2027                    (HFast & (INTRINSIC|TIMEOUT)) &&
2028                    !defends(AD_SLOW, uwep) && !rn2(4))
2029
2030                     u_slow_down();
2031                     stop_occupation();
2032                 break;
2033 #endif
2034             default: impossible("Gaze attack %d?", mattk->adtyp);
2035                 break;
2036         }
2037         return(0);
2038 }
2039
2040 #endif /* OVLB */
2041 #ifdef OVL1
2042
2043 void
2044 mdamageu(mtmp, n)       /* mtmp hits you for n points damage */
2045 register struct monst *mtmp;
2046 register int n;
2047 {
2048         flags.botl = 1;
2049         if (Upolyd) {
2050                 u.mh -= n;
2051                 if (u.mh < 1) rehumanize();
2052         } else {
2053                 u.uhp -= n;
2054                 if(u.uhp < 1) done_in_by(mtmp);
2055         }
2056 }
2057
2058 #endif /* OVL1 */
2059 #ifdef OVLB
2060
2061 STATIC_OVL void
2062 urustm(mon, obj)
2063 register struct monst *mon;
2064 register struct obj *obj;
2065 {
2066         boolean vis;
2067         boolean is_acid;
2068
2069         if (!mon || !obj) return; /* just in case */
2070         if (dmgtype(youmonst.data, AD_CORR))
2071             is_acid = TRUE;
2072         else if (dmgtype(youmonst.data, AD_RUST))
2073             is_acid = FALSE;
2074         else
2075             return;
2076
2077         vis = cansee(mon->mx, mon->my);
2078
2079         if ((is_acid ? is_corrodeable(obj) : is_rustprone(obj)) &&
2080             (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) {
2081                 if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) {
2082                     if (vis)
2083                         pline("Somehow, %s weapon is not affected.",
2084                                                 s_suffix(mon_nam(mon)));
2085                     if (obj->greased && !rn2(2)) obj->greased = 0;
2086                 } else {
2087                     if (vis)
2088                         pline("%s %s%s!",
2089                                 s_suffix(Monnam(mon)),
2090                                 aobjnam(obj, (is_acid ? "corrode" : "rust")),
2091                                 (is_acid ? obj->oeroded2 : obj->oeroded)
2092                                     ? " further" : "");
2093                     if (is_acid) obj->oeroded2++;
2094                     else obj->oeroded++;
2095                 }
2096         }
2097 }
2098
2099 #endif /* OVLB */
2100 #ifdef OVL1
2101
2102 int
2103 could_seduce(magr,mdef,mattk)
2104 struct monst *magr, *mdef;
2105 struct attack *mattk;
2106 /* returns 0 if seduction impossible,
2107  *         1 if fine,
2108  *         2 if wrong gender for nymph */
2109 {
2110         register struct permonst *pagr;
2111         boolean agrinvis, defperc;
2112         xchar genagr, gendef;
2113
2114         if (is_animal(magr->data)) return (0);
2115         if(magr == &youmonst) {
2116                 pagr = youmonst.data;
2117                 agrinvis = (Invis != 0);
2118                 genagr = poly_gender();
2119         } else {
2120                 pagr = magr->data;
2121                 agrinvis = magr->minvis;
2122                 genagr = gender(magr);
2123         }
2124         if(mdef == &youmonst) {
2125                 defperc = (See_invisible != 0);
2126                 gendef = poly_gender();
2127         } else {
2128                 defperc = perceives(mdef->data);
2129                 gendef = gender(mdef);
2130         }
2131
2132         if(agrinvis && !defperc
2133 #ifdef SEDUCE
2134                 && mattk && mattk->adtyp != AD_SSEX
2135 #endif
2136                 )
2137                 return 0;
2138
2139         if(pagr->mlet != S_NYMPH
2140                 && ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
2141 #ifdef SEDUCE
2142                     || (mattk && mattk->adtyp != AD_SSEX)
2143 #endif
2144                    ))
2145                 return 0;
2146         
2147         if(genagr == 1 - gendef)
2148                 return 1;
2149         else
2150                 return (pagr->mlet == S_NYMPH) ? 2 : 0;
2151 }
2152
2153 #endif /* OVL1 */
2154 #ifdef OVLB
2155
2156 #ifdef SEDUCE
2157 /* Returns 1 if monster teleported */
2158 int
2159 doseduce(mon)
2160 register struct monst *mon;
2161 {
2162         register struct obj *ring, *nring;
2163         boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */
2164         char qbuf[QBUFSZ];
2165
2166         if (mon->mcan || mon->mspec_used) {
2167                 pline("%s acts as though %s has got a %sheadache.",
2168                       Monnam(mon), mhe(mon),
2169                       mon->mcan ? "severe " : "");
2170                 return 0;
2171         }
2172
2173         if (unconscious()) {
2174                 pline("%s seems dismayed at your lack of response.",
2175                       Monnam(mon));
2176                 return 0;
2177         }
2178
2179         if (Blind) pline("It caresses you...");
2180         else You_feel("very attracted to %s.", mon_nam(mon));
2181
2182         for(ring = invent; ring; ring = nring) {
2183             nring = ring->nobj;
2184             if (ring->otyp != RIN_ADORNMENT) continue;
2185             if (fem) {
2186                 if (rn2(20) < ACURR(A_CHA)) {
2187                     Sprintf(qbuf, "\"That %s looks pretty.  May I have it?\"",
2188                         safe_qbuf("",sizeof("\"That  looks pretty.  May I have it?\""),
2189                         xname(ring), simple_typename(ring->otyp), "ring"));
2190                     makeknown(RIN_ADORNMENT);
2191                     if (yn(qbuf) == 'n') continue;
2192                 } else pline("%s decides she'd like your %s, and takes it.",
2193                         Blind ? "She" : Monnam(mon), xname(ring));
2194                 makeknown(RIN_ADORNMENT);
2195                 if (ring==uleft || ring==uright) Ring_gone(ring);
2196                 if (ring==uwep) setuwep((struct obj *)0);
2197                 if (ring==uswapwep) setuswapwep((struct obj *)0);
2198                 if (ring==uquiver) setuqwep((struct obj *)0);
2199                 freeinv(ring);
2200                 (void) mpickobj(mon,ring);
2201             } else {
2202                 char buf[BUFSZ];
2203
2204                 if (uleft && uright && uleft->otyp == RIN_ADORNMENT
2205                                 && uright->otyp==RIN_ADORNMENT)
2206                         break;
2207                 if (ring==uleft || ring==uright) continue;
2208                 if (rn2(20) < ACURR(A_CHA)) {
2209                     Sprintf(qbuf,"\"That %s looks pretty.  Would you wear it for me?\"",
2210                         safe_qbuf("",
2211                             sizeof("\"That  looks pretty.  Would you wear it for me?\""),
2212                             xname(ring), simple_typename(ring->otyp), "ring"));
2213                     makeknown(RIN_ADORNMENT);
2214                     if (yn(qbuf) == 'n') continue;
2215                 } else {
2216                     pline("%s decides you'd look prettier wearing your %s,",
2217                         Blind ? "He" : Monnam(mon), xname(ring));
2218                     pline("and puts it on your finger.");
2219                 }
2220                 makeknown(RIN_ADORNMENT);
2221                 if (!uright) {
2222                     pline("%s puts %s on your right %s.",
2223                         Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
2224                     setworn(ring, RIGHT_RING);
2225                 } else if (!uleft) {
2226                     pline("%s puts %s on your left %s.",
2227                         Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
2228                     setworn(ring, LEFT_RING);
2229                 } else if (uright && uright->otyp != RIN_ADORNMENT) {
2230                     Strcpy(buf, xname(uright));
2231                     pline("%s replaces your %s with your %s.",
2232                         Blind ? "He" : Monnam(mon), buf, xname(ring));
2233                     Ring_gone(uright);
2234                     setworn(ring, RIGHT_RING);
2235                 } else if (uleft && uleft->otyp != RIN_ADORNMENT) {
2236                     Strcpy(buf, xname(uleft));
2237                     pline("%s replaces your %s with your %s.",
2238                         Blind ? "He" : Monnam(mon), buf, xname(ring));
2239                     Ring_gone(uleft);
2240                     setworn(ring, LEFT_RING);
2241                 } else impossible("ring replacement");
2242                 Ring_on(ring);
2243                 prinv((char *)0, ring, 0L);
2244             }
2245         }
2246
2247         if (!uarmc && !uarmf && !uarmg && !uarms && !uarmh
2248 #ifdef TOURIST
2249                                                                 && !uarmu
2250 #endif
2251                                                                         )
2252                 pline("%s murmurs sweet nothings into your ear.",
2253                         Blind ? (fem ? "She" : "He") : Monnam(mon));
2254         else
2255                 pline("%s murmurs in your ear, while helping you undress.",
2256                         Blind ? (fem ? "She" : "He") : Monnam(mon));
2257         mayberem(uarmc, cloak_simple_name(uarmc));
2258         if(!uarmc)
2259                 mayberem(uarm, "suit");
2260         mayberem(uarmf, "boots");
2261         if(!uwep || !welded(uwep))
2262                 mayberem(uarmg, "gloves");
2263         mayberem(uarms, "shield");
2264         mayberem(uarmh, "helmet");
2265 #ifdef TOURIST
2266         if(!uarmc && !uarm)
2267                 mayberem(uarmu, "shirt");
2268 #endif
2269
2270         if (uarm || uarmc) {
2271                 verbalize("You're such a %s; I wish...",
2272                                 flags.female ? "sweet lady" : "nice guy");
2273                 if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
2274                 return 1;
2275         }
2276         if (u.ualign.type == A_CHAOTIC)
2277                 adjalign(1);
2278
2279         /* by this point you have discovered mon's identity, blind or not... */
2280         pline("Time stands still while you and %s lie in each other's arms...",
2281                 noit_mon_nam(mon));
2282         if (rn2(35) > ACURR(A_CHA) + ACURR(A_INT)) {
2283                 /* Don't bother with mspec_used here... it didn't get tired! */
2284                 pline("%s seems to have enjoyed it more than you...",
2285                         noit_Monnam(mon));
2286                 switch (rn2(5)) {
2287                         case 0: You_feel("drained of energy.");
2288                                 u.uen = 0;
2289                                 u.uenmax -= rnd(Half_physical_damage ? 5 : 10);
2290                                 exercise(A_CON, FALSE);
2291                                 if (u.uenmax < 0) u.uenmax = 0;
2292                                 break;
2293                         case 1: You("are down in the dumps.");
2294                                 (void) adjattrib(A_CON, -1, TRUE);
2295                                 exercise(A_CON, FALSE);
2296                                 flags.botl = 1;
2297                                 break;
2298                         case 2: Your("senses are dulled.");
2299                                 (void) adjattrib(A_WIS, -1, TRUE);
2300                                 exercise(A_WIS, FALSE);
2301                                 flags.botl = 1;
2302                                 break;
2303                         case 3:
2304                                 if (!resists_drli(&youmonst)) {
2305                                     You_feel("out of shape.");
2306                                     losexp("overexertion");
2307                                 } else {
2308                                     You("have a curious feeling...");
2309                                 }
2310                                 break;
2311                         case 4: {
2312                                 int tmp;
2313                                 You_feel("exhausted.");
2314                                 exercise(A_STR, FALSE);
2315                                 tmp = rn1(10, 6);
2316                                 if(Half_physical_damage) tmp = (tmp+1) / 2;
2317                                 losehp(tmp, "exhaustion", KILLED_BY);
2318                                 break;
2319                         }
2320                 }
2321         } else {
2322                 mon->mspec_used = rnd(100); /* monster is worn out */
2323                 You("seem to have enjoyed it more than %s...",
2324                     noit_mon_nam(mon));
2325                 switch (rn2(5)) {
2326                 case 0: You_feel("raised to your full potential.");
2327                         exercise(A_CON, TRUE);
2328                         u.uen = (u.uenmax += rnd(5));
2329                         break;
2330                 case 1: You_feel("good enough to do it again.");
2331                         (void) adjattrib(A_CON, 1, TRUE);
2332                         exercise(A_CON, TRUE);
2333                         flags.botl = 1;
2334                         break;
2335                 case 2: You("will always remember %s...", noit_mon_nam(mon));
2336                         (void) adjattrib(A_WIS, 1, TRUE);
2337                         exercise(A_WIS, TRUE);
2338                         flags.botl = 1;
2339                         break;
2340                 case 3: pline("That was a very educational experience.");
2341                         pluslvl(FALSE);
2342                         exercise(A_WIS, TRUE);
2343                         break;
2344                 case 4: You_feel("restored to health!");
2345                         u.uhp = u.uhpmax;
2346                         if (Upolyd) u.mh = u.mhmax;
2347                         exercise(A_STR, TRUE);
2348                         flags.botl = 1;
2349                         break;
2350                 }
2351         }
2352
2353         if (mon->mtame) /* don't charge */ ;
2354         else if (rn2(20) < ACURR(A_CHA)) {
2355                 pline("%s demands that you pay %s, but you refuse...",
2356                         noit_Monnam(mon),
2357                         Blind ? (fem ? "her" : "him") : mhim(mon));
2358         } else if (u.umonnum == PM_LEPRECHAUN)
2359                 pline("%s tries to take your money, but fails...",
2360                                 noit_Monnam(mon));
2361         else {
2362 #ifndef GOLDOBJ
2363                 long cost;
2364
2365                 if (u.ugold > (long)LARGEST_INT - 10L)
2366                         cost = (long) rnd(LARGEST_INT) + 500L;
2367                 else
2368                         cost = (long) rnd((int)u.ugold + 10) + 500L;
2369                 if (mon->mpeaceful) {
2370                         cost /= 5L;
2371                         if (!cost) cost = 1L;
2372                 }
2373                 if (cost > u.ugold) cost = u.ugold;
2374                 if (!cost) verbalize("It's on the house!");
2375                 else {
2376                     pline("%s takes %ld %s for services rendered!",
2377                             noit_Monnam(mon), cost, currency(cost));
2378                     u.ugold -= cost;
2379                     mon->mgold += cost;
2380                     flags.botl = 1;
2381                 }
2382 #else
2383                 long cost;
2384                 long umoney = money_cnt(invent);
2385
2386                 if (umoney > (long)LARGEST_INT - 10L)
2387                         cost = (long) rnd(LARGEST_INT) + 500L;
2388                 else
2389                         cost = (long) rnd((int)umoney + 10) + 500L;
2390                 if (mon->mpeaceful) {
2391                         cost /= 5L;
2392                         if (!cost) cost = 1L;
2393                 }
2394                 if (cost > umoney) cost = umoney;
2395                 if (!cost) verbalize("It's on the house!");
2396                 else { 
2397                     pline("%s takes %ld %s for services rendered!",
2398                             noit_Monnam(mon), cost, currency(cost));
2399                     money2mon(mon, cost);
2400                     flags.botl = 1;
2401                 }
2402 #endif
2403         }
2404         if (!rn2(25)) mon->mcan = 1; /* monster is worn out */
2405         if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
2406         return 1;
2407 }
2408
2409 STATIC_OVL void
2410 mayberem(obj, str)
2411 register struct obj *obj;
2412 const char *str;
2413 {
2414         char qbuf[QBUFSZ];
2415
2416         if (!obj || !obj->owornmask) return;
2417
2418         if (rn2(20) < ACURR(A_CHA)) {
2419                 Sprintf(qbuf,"\"Shall I remove your %s, %s?\"",
2420                         str,
2421                         (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart"));
2422                 if (yn(qbuf) == 'n') return;
2423         } else {
2424                 char hairbuf[BUFSZ];
2425
2426                 Sprintf(hairbuf, "let me run my fingers through your %s",
2427                         body_part(HAIR));
2428                 verbalize("Take off your %s; %s.", str,
2429                         (obj == uarm)  ? "let's get a little closer" :
2430                         (obj == uarmc || obj == uarms) ? "it's in the way" :
2431                         (obj == uarmf) ? "let me rub your feet" :
2432                         (obj == uarmg) ? "they're too clumsy" :
2433 #ifdef TOURIST
2434                         (obj == uarmu) ? "let me massage you" :
2435 #endif
2436                         /* obj == uarmh */
2437                         hairbuf);
2438         }
2439         remove_worn_item(obj, TRUE);
2440 }
2441 #endif  /* SEDUCE */
2442
2443 #endif /* OVLB */
2444
2445 #ifdef OVL1
2446
2447 STATIC_OVL int
2448 passiveum(olduasmon,mtmp,mattk)
2449 struct permonst *olduasmon;
2450 register struct monst *mtmp;
2451 register struct attack *mattk;
2452 {
2453         int i, tmp;
2454
2455         for (i = 0; ; i++) {
2456             if (i >= NATTK) return 1;
2457             if (olduasmon->mattk[i].aatyp == AT_NONE ||
2458                         olduasmon->mattk[i].aatyp == AT_BOOM) break;
2459         }
2460         if (olduasmon->mattk[i].damn)
2461             tmp = d((int)olduasmon->mattk[i].damn,
2462                                     (int)olduasmon->mattk[i].damd);
2463         else if(olduasmon->mattk[i].damd)
2464             tmp = d((int)olduasmon->mlevel+1, (int)olduasmon->mattk[i].damd);
2465         else
2466             tmp = 0;
2467
2468         /* These affect the enemy even if you were "killed" (rehumanized) */
2469         switch(olduasmon->mattk[i].adtyp) {
2470             case AD_ACID:
2471                 if (!rn2(2)) {
2472                     pline("%s is splashed by your acid!", Monnam(mtmp));
2473                     if (resists_acid(mtmp)) {
2474                         pline("%s is not affected.", Monnam(mtmp));
2475                         tmp = 0;
2476                     }
2477                 } else tmp = 0;
2478                 if (!rn2(30)) erode_armor(mtmp, TRUE);
2479                 if (!rn2(6)) erode_obj(MON_WEP(mtmp), TRUE, TRUE);
2480                 goto assess_dmg;
2481             case AD_STON: /* cockatrice */
2482             {
2483                 long protector = attk_protection((int)mattk->aatyp),
2484                      wornitems = mtmp->misc_worn_check;
2485
2486                 /* wielded weapon gives same protection as gloves here */
2487                 if (MON_WEP(mtmp) != 0) wornitems |= W_ARMG;
2488
2489                 if (!resists_ston(mtmp) && (protector == 0L ||
2490                         (protector != ~0L &&
2491                             (wornitems & protector) != protector))) {
2492                     if (poly_when_stoned(mtmp->data)) {
2493                         mon_to_stone(mtmp);
2494                         return (1);
2495                     }
2496                     pline("%s turns to stone!", Monnam(mtmp));
2497                     stoned = 1;
2498                     xkilled(mtmp, 0);
2499                     if (mtmp->mhp > 0) return 1;
2500                     return 2;
2501                 }
2502                 return 1;
2503             }
2504             case AD_ENCH:       /* KMH -- remove enchantment (disenchanter) */
2505                 if (otmp) {
2506                     (void) drain_item(otmp);
2507                     /* No message */
2508                 }
2509                 return (1);
2510             default:
2511                 break;
2512         }
2513         if (!Upolyd) return 1;
2514
2515         /* These affect the enemy only if you are still a monster */
2516         if (rn2(3)) switch(youmonst.data->mattk[i].adtyp) {
2517             case AD_PHYS:
2518                 if (youmonst.data->mattk[i].aatyp == AT_BOOM) {
2519                     You("explode!");
2520                     /* KMH, balance patch -- this is okay with unchanging */
2521                     rehumanize();
2522                     goto assess_dmg;
2523                 }
2524                 break;
2525             case AD_PLYS: /* Floating eye */
2526                 if (tmp > 127) tmp = 127;
2527                 if (u.umonnum == PM_FLOATING_EYE) {
2528                     if (!rn2(4)) tmp = 127;
2529                     if (mtmp->mcansee && haseyes(mtmp->data) && rn2(3) &&
2530                                 (perceives(mtmp->data) || !Invis)) {
2531                         if (Blind)
2532                             pline("As a blind %s, you cannot defend yourself.",
2533                                                         youmonst.data->mname);
2534                         else {
2535                             if (mon_reflects(mtmp,
2536                                             "Your gaze is reflected by %s %s."))
2537                                 return 1;
2538                             pline("%s is frozen by your gaze!", Monnam(mtmp));
2539                             mtmp->mcanmove = 0;
2540                             mtmp->mfrozen = tmp;
2541                             return 3;
2542                         }
2543                     }
2544                 } else { /* gelatinous cube */
2545                     pline("%s is frozen by you.", Monnam(mtmp));
2546                     mtmp->mcanmove = 0;
2547                     mtmp->mfrozen = tmp;
2548                     return 3;
2549                 }
2550                 return 1;
2551             case AD_COLD: /* Brown mold or blue jelly */
2552                 if (resists_cold(mtmp)) {
2553                     shieldeff(mtmp->mx, mtmp->my);
2554                     pline("%s is mildly chilly.", Monnam(mtmp));
2555                     golemeffects(mtmp, AD_COLD, tmp);
2556                     tmp = 0;
2557                     break;
2558                 }
2559                 pline("%s is suddenly very cold!", Monnam(mtmp));
2560                 u.mh += tmp / 2;
2561                 if (u.mhmax < u.mh) u.mhmax = u.mh;
2562                 if (u.mhmax > ((youmonst.data->mlevel+1) * 8))
2563                     (void)split_mon(&youmonst, mtmp);
2564                 break;
2565             case AD_STUN: /* Yellow mold */
2566                 if (!mtmp->mstun) {
2567                     mtmp->mstun = 1;
2568                     pline("%s %s.", Monnam(mtmp),
2569                           makeplural(stagger(mtmp->data, "stagger")));
2570                 }
2571                 tmp = 0;
2572                 break;
2573             case AD_FIRE: /* Red mold */
2574                 if (resists_fire(mtmp)) {
2575                     shieldeff(mtmp->mx, mtmp->my);
2576                     pline("%s is mildly warm.", Monnam(mtmp));
2577                     golemeffects(mtmp, AD_FIRE, tmp);
2578                     tmp = 0;
2579                     break;
2580                 }
2581                 pline("%s is suddenly very hot!", Monnam(mtmp));
2582                 break;
2583             case AD_ELEC:
2584                 if (resists_elec(mtmp)) {
2585                     shieldeff(mtmp->mx, mtmp->my);
2586                     pline("%s is slightly tingled.", Monnam(mtmp));
2587                     golemeffects(mtmp, AD_ELEC, tmp);
2588                     tmp = 0;
2589                     break;
2590                 }
2591                 pline("%s is jolted with your electricity!", Monnam(mtmp));
2592                 break;
2593             default: tmp = 0;
2594                 break;
2595         }
2596         else tmp = 0;
2597
2598     assess_dmg:
2599         if((mtmp->mhp -= tmp) <= 0) {
2600                 pline("%s dies!", Monnam(mtmp));
2601                 xkilled(mtmp,0);
2602                 if (mtmp->mhp > 0) return 1;
2603                 return 2;
2604         }
2605         return 1;
2606 }
2607
2608 #endif /* OVL1 */
2609 #ifdef OVLB
2610
2611 #include "edog.h"
2612 struct monst *
2613 cloneu()
2614 {
2615         register struct monst *mon;
2616         int mndx = monsndx(youmonst.data);
2617
2618         if (u.mh <= 1) return(struct monst *)0;
2619         if (mvitals[mndx].mvflags & G_EXTINCT) return(struct monst *)0;
2620         mon = makemon(youmonst.data, u.ux, u.uy, NO_MINVENT|MM_EDOG);
2621         mon = christen_monst(mon, plname);
2622         initedog(mon);
2623         mon->m_lev = youmonst.data->mlevel;
2624         mon->mhpmax = u.mhmax;
2625         mon->mhp = u.mh / 2;
2626         u.mh -= mon->mhp;
2627         flags.botl = 1;
2628         return(mon);
2629 }
2630
2631 #endif /* OVLB */
2632
2633 /*mhitu.c*/