]> granicus.if.org Git - nethack/commitdiff
fix B16006 - cancelled monster-monster attacks
authornethack.rankin <nethack.rankin>
Sat, 4 Jan 2003 02:29:35 +0000 (02:29 +0000)
committernethack.rankin <nethack.rankin>
Sat, 4 Jan 2003 02:29:35 +0000 (02:29 +0000)
     Various damage types which wouldn't work when a cancelled monster
attacks the player were working when it attacked other monsters instead.
Besides attempting to fix that, this also makes cloaks and other magic
blocking armor ("magic cancellation factor") work for monsters similar
to the way it works for the player.

     Most types of damage appear to revert to physical damage when the
attacker is cancelled; I'm not sure that's appropriate in many of the
instances.  The leg-pricking case was clearly wrong, since it gives
messages about the attack failing yet still hurt the character.

     This really needs a lot more testing than I have energy for.  I've
tried to clean up various inconsistencies and may have made some typos
in the process.

doc/fixes34.1
include/extern.h
src/mhitm.c
src/mhitu.c
src/uhitm.c

index e2b5b12b7874ae7365afe53977b83ddc11535e51..3eef1b57fed23d64ab45c8d2109ddf99d2f3b7bc 100644 (file)
@@ -345,6 +345,8 @@ avoid discrepancies in size and associated armor-wearing ability between
        by forcing newman() if poly-target matches your_race()
 add missing data.base entries for caveman, healer, monk, priest, and samurai
 allow "grey spellbook" as alternative spelling of "gray spellbook"
+handle attacks by cancelled monsters more consistently
+armor worn by monsters might negate some magic attacks like it does for hero
 
 
 Platform- and/or Interface-Specific Fixes
index 1c292041766da60827a387fbd6b911ebd8de95d8..0b8fb70d195f05fa59368087cb977f1ce721276c 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)extern.h   3.4     2002/08/22      */
+/*     SCCS Id: @(#)extern.h   3.4     2003/01/02      */
 /* Copyright (c) Steve Creps, 1988.                              */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -954,6 +954,7 @@ E struct monst *NDECL(cloneu);
 E void FDECL(expels, (struct monst *,struct permonst *,BOOLEAN_P));
 E struct attack *FDECL(getmattk, (struct permonst *,int,int *,struct attack *));
 E int FDECL(mattacku, (struct monst *));
+E int FDECL(magic_negation, (struct monst *));
 E int FDECL(gazemu, (struct monst *,struct attack *));
 E void FDECL(mdamageu, (struct monst *,int));
 E int FDECL(could_seduce, (struct monst *,struct monst *,struct attack *));
index 8cae9ed84681208703b41266a0a1499bcf54ebaf..ca47ca082db2cf5234746b4e869383a7ca3c67f7 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)mhitm.c    3.4     2002/12/09      */
+/*     SCCS Id: @(#)mhitm.c    3.4     2003/01/02      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -573,7 +573,8 @@ mdamagem(magr, mdef, mattk)
        struct obj *obj;
        char buf[BUFSZ];
        struct permonst *pa = magr->data, *pd = mdef->data;
-       int num, tmp = d((int)mattk->damn, (int)mattk->damd);
+       int armpro, num, tmp = d((int)mattk->damn, (int)mattk->damd);
+       boolean cancelled;
 
        if (touch_petrifies(pd) && !resists_ston(magr)) {
            long protector = attk_protection(mattk->aatyp),
@@ -597,6 +598,10 @@ mdamagem(magr, mdef, mattk)
            }
        }
 
+       /* cancellation factor is the same as when attacking the hero */
+       armpro = magic_negation(mdef);
+       cancelled = magr->mcan || !((rn2(3) >= armpro) || !rn2(50));
+
        switch(mattk->adtyp) {
            case AD_DGST:
                /* eating a Rider or its corpse is fatal */
@@ -650,18 +655,24 @@ mdamagem(magr, mdef, mattk)
                    pline("%s %s for a moment.", Monnam(mdef),
                          makeplural(stagger(mdef->data, "stagger")));
                mdef->mstun = 1;
-               /* fall through */
+               goto physical;
+           case AD_LEGS:
+               if (magr->mcan) {
+                   tmp = 0;
+                   break;
+               }
+               goto physical;
            case AD_WERE:
            case AD_HEAL:
-           case AD_LEGS:
            case AD_PHYS:
-               if (mattk->aatyp == AT_KICK && thick_skinned(pd))
-                       tmp = 0;
-               else if(mattk->aatyp == AT_WEAP) {
+ physical:
+               if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
+                   tmp = 0;
+               } else if(mattk->aatyp == AT_WEAP) {
                    if(otmp) {
                        if (otmp->otyp == CORPSE &&
                                touch_petrifies(&mons[otmp->corpsenm]))
-                           goto do_stone_goto_label;
+                           goto do_stone;
                        tmp += dmgval(otmp, mdef);
                        if (otmp->oartifact) {
                            (void)artifact_hit(magr,mdef, otmp, &tmp, dieroll);
@@ -682,7 +693,7 @@ mdamagem(magr, mdef, mattk)
                }
                break;
            case AD_FIRE:
-               if (magr->mcan) {
+               if (cancelled) {
                    tmp = 0;
                    break;
                }
@@ -713,7 +724,7 @@ mdamagem(magr, mdef, mattk)
                tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
                break;
            case AD_COLD:
-               if (magr->mcan) {
+               if (cancelled) {
                    tmp = 0;
                    break;
                }
@@ -729,7 +740,7 @@ mdamagem(magr, mdef, mattk)
                tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
                break;
            case AD_ELEC:
-               if (magr->mcan) {
+               if (cancelled) {
                    tmp = 0;
                    break;
                }
@@ -762,7 +773,8 @@ mdamagem(magr, mdef, mattk)
                if (!rn2(6)) erode_obj(MON_WEP(mdef), TRUE, TRUE);
                break;
            case AD_RUST:
-               if (!magr->mcan && pd == &mons[PM_IRON_GOLEM]) {
+               if (magr->mcan) break;
+               if (pd == &mons[PM_IRON_GOLEM]) {
                        if (vis) pline("%s falls to pieces!", Monnam(mdef));
                        mondied(mdef);
                        if (mdef->mhp > 0) return 0;
@@ -776,13 +788,15 @@ mdamagem(magr, mdef, mattk)
                tmp = 0;
                break;
            case AD_CORR:
+               if (magr->mcan) break;
                hurtmarmor(mdef, AD_CORR);
                mdef->mstrategy &= ~STRAT_WAITFORU;
                tmp = 0;
                break;
            case AD_DCAY:
-               if (!magr->mcan && (pd == &mons[PM_WOOD_GOLEM] ||
-                   pd == &mons[PM_LEATHER_GOLEM])) {
+               if (magr->mcan) break;
+               if (pd == &mons[PM_WOOD_GOLEM] ||
+                   pd == &mons[PM_LEATHER_GOLEM]) {
                        if (vis) pline("%s falls to pieces!", Monnam(mdef));
                        mondied(mdef);
                        if (mdef->mhp > 0) return 0;
@@ -796,9 +810,10 @@ mdamagem(magr, mdef, mattk)
                tmp = 0;
                break;
            case AD_STON:
-do_stone_goto_label:
+               if (magr->mcan) break;
+ do_stone:
                /* may die from the acid if it eats a stone-curing corpse */
-               if (munstone(mdef, FALSE)) goto label2;
+               if (munstone(mdef, FALSE)) goto post_stone;
                if (poly_when_stoned(pd)) {
                        mon_to_stone(mdef);
                        tmp = 0;
@@ -807,7 +822,7 @@ do_stone_goto_label:
                if (!resists_ston(mdef)) {
                        if (vis) pline("%s turns to stone!", Monnam(mdef));
                        monstone(mdef);
-label2:                        if (mdef->mhp > 0) return 0;
+ post_stone:           if (mdef->mhp > 0) return 0;
                        else if (mdef->mtame && !vis)
                            You(brief_feeling, "peculiarly sad");
                        return (MM_DEF_DIED | (grow_up(magr,mdef) ?
@@ -816,7 +831,7 @@ label2:                     if (mdef->mhp > 0) return 0;
                tmp = (mattk->adtyp == AD_STON ? 0 : 1);
                break;
            case AD_TLPT:
-               if (!magr->mcan && tmp < mdef->mhp && !tele_restrict(mdef)) {
+               if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) {
                    char mdef_Monnam[BUFSZ];
                    /* save the name before monster teleports, otherwise
                       we'll get "it" in the suddenly disappears message */
@@ -832,7 +847,7 @@ label2:                     if (mdef->mhp > 0) return 0;
                }
                break;
            case AD_SLEE:
-               if (!magr->mcan && !mdef->msleeping &&
+               if (!cancelled && !mdef->msleeping &&
                        sleep_monst(mdef, rnd(10), -1)) {
                    if (vis) {
                        Strcpy(buf, Monnam(mdef));
@@ -843,7 +858,7 @@ label2:                     if (mdef->mhp > 0) return 0;
                }
                break;
            case AD_PLYS:
-               if(!magr->mcan && mdef->mcanmove) {
+               if(!cancelled && mdef->mcanmove) {
                    if (vis) {
                        Strcpy(buf, Monnam(mdef));
                        pline("%s is frozen by %s.", buf, mon_nam(magr));
@@ -854,7 +869,7 @@ label2:                     if (mdef->mhp > 0) return 0;
                }
                break;
            case AD_SLOW:
-               if (!magr->mcan && vis && mdef->mspeed != MSLOW) {
+               if (!cancelled && mdef->mspeed != MSLOW) {
                    unsigned int oldspeed = mdef->mspeed;
 
                    mon_adjust_speed(mdef, -1, (struct obj *)0);
@@ -956,7 +971,7 @@ label2:                     if (mdef->mhp > 0) return 0;
                }
                break;
            case AD_DRLI:
-               if (rn2(2) && !resists_drli(mdef)) {
+               if (!cancelled && !rn2(3) && !resists_drli(mdef)) {
                        tmp = d(2,6);
                        if (vis)
                            pline("%s suddenly seems weaker!", Monnam(mdef));
@@ -972,13 +987,13 @@ label2:                   if (mdef->mhp > 0) return 0;
 #endif
            case AD_SITM:       /* for now these are the same */
            case AD_SEDU:
+               if (magr->mcan) break;
                /* find an object to steal, non-cursed if magr is tame */
-               for (obj = mdef->minvent; obj; obj = obj->nobj) {
+               for (obj = mdef->minvent; obj; obj = obj->nobj)
                    if (!magr->mtame || !obj->cursed)
                        break;
-               }
 
-               if (!magr->mcan && obj) {
+               if (obj) {
                        char onambuf[BUFSZ], mdefnambuf[BUFSZ];
 
                        /* make a special x_monnam() call that never omits
@@ -1027,7 +1042,7 @@ label2:                   if (mdef->mhp > 0) return 0;
            case AD_DRST:
            case AD_DRDX:
            case AD_DRCO:
-               if (!magr->mcan && !rn2(8)) {
+               if (!cancelled && !rn2(8)) {
                    if (vis)
                        pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
                              mpoisons_subj(magr, mattk));
@@ -1075,18 +1090,25 @@ label2:                 if (mdef->mhp > 0) return 0;
                                  s_suffix(Monnam(mdef)));
                break;
            case AD_SLIM:
-               if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
-                               mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
-                               mdef->data != &mons[PM_SALAMANDER] &&
-                               mdef->data != &mons[PM_GREEN_SLIME]) {
-                   (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis);
+               if (cancelled) break;   /* physical damage only */
+               if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
+                               mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
+                               mdef->data != &mons[PM_SALAMANDER] &&
+                               mdef->data != &mons[PM_GREEN_SLIME]) {
+                   (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis);
                    mdef->mstrategy &= ~STRAT_WAITFORU;
-                   tmp = 0;
-               }
-               break;
+                   tmp = 0;
+               }
+               break;
            case AD_STCK:
+               if (cancelled) tmp = 0;
+               break;
            case AD_WRAP: /* monsters cannot grab one another, it's too hard */
-           case AD_ENCH: /* There's no msomearmor() function, so just do damage */
+               if (magr->mcan) tmp = 0;
+               break;
+           case AD_ENCH:
+               /* there's no msomearmor() function, so just do damage */
+            /* if (cancelled) break; */
                break;
            default:    tmp = 0;
                        break;
index 4eafbe9abaa4e2034cde30857584b96bc652d956..f67d8664e0b6a32c55bbc67f639fe1ed4303c8c6 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)mhitu.c    3.4     2002/12/09      */
+/*     SCCS Id: @(#)mhitu.c    3.4     2003/01/02      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -789,6 +789,51 @@ struct attack *mattk;
        return FALSE;
 }
 
+/* armor that sufficiently covers the body might be able to block magic */
+int
+magic_negation(mon)
+struct monst *mon;
+{
+       struct obj *armor;
+       int armpro = 0;
+
+       armor = (mon == &youmonst) ? uarm : which_armor(mon, W_ARM);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+       armor = (mon == &youmonst) ? uarmc : which_armor(mon, W_ARMC);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+       armor = (mon == &youmonst) ? uarmh : which_armor(mon, W_ARMH);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+
+       /* armor types for shirt, gloves, shoes, and shield don't currently
+          provide any magic cancellation but we might as well be complete */
+#ifdef TOURIST
+       armor = (mon == &youmonst) ? uarmu : which_armor(mon, W_ARMU);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+#endif
+       armor = (mon == &youmonst) ? uarmg : which_armor(mon, W_ARMG);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+       armor = (mon == &youmonst) ? uarmf : which_armor(mon, W_ARMF);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+       armor = (mon == &youmonst) ? uarms : which_armor(mon, W_ARMS);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+
+#ifdef STEED
+       /* this one is really a stretch... */
+       armor = (mon == &youmonst) ? 0 : which_armor(mon, W_SADDLE);
+       if (armor && armpro < objects[armor->otyp].a_can)
+           armpro = objects[armor->otyp].a_can;
+#endif
+
+       return armpro;
+}
+
 /*
  * hitmu: monster hits you
  *       returns 2 if monster dies (e.g. "yellow light"), 1 otherwise
@@ -842,13 +887,7 @@ hitmu(mtmp, mattk)
 /*     Use uncancelled when the cancellation factor takes into account certain
  *     armor's special magic protection.  Otherwise just use !mtmp->mcan.
  */
-       armpro = 0;
-       if (uarm && armpro < objects[uarm->otyp].a_can)
-               armpro = objects[uarm->otyp].a_can;
-       if (uarmc && armpro < objects[uarmc->otyp].a_can)
-               armpro = objects[uarmc->otyp].a_can;
-       if (uarmh && armpro < objects[uarmh->otyp].a_can)
-               armpro = objects[uarmh->otyp].a_can;
+       armpro = magic_negation(&youmonst);
        uncancelled = !mtmp->mcan && ((rn2(3) >= armpro) || !rn2(50));
 
        permdmg = 0;
@@ -1053,14 +1092,15 @@ dopois:
            case AD_PLYS:
                hitmsg(mtmp, mattk);
                if (uncancelled && multi >= 0 && !rn2(3)) {
-               if (Free_action) You("momentarily stiffen.");            
-               else {
-                   if (Blind) You("are frozen!");
-                   else You("are frozen by %s!", mon_nam(mtmp));
-                   nomovemsg = 0;      /* default: "you can move again" */
-                   nomul(-rnd(10));
-                   exercise(A_DEX, FALSE);
-               }
+                   if (Free_action) {
+                       You("momentarily stiffen.");            
+                   } else {
+                       if (Blind) You("are frozen!");
+                       else You("are frozen by %s!", mon_nam(mtmp));
+                       nomovemsg = 0;  /* default: "you can move again" */
+                       nomul(-rnd(10));
+                       exercise(A_DEX, FALSE);
+                   }
                }
                break;
            case AD_DRLI:
@@ -1076,6 +1116,7 @@ dopois:
                /* This case is too obvious to ignore, but Nethack is not in
                 * general very good at considering height--most short monsters
                 * still _can_ attack you when you're flying or mounted.
+                * [FIXME: why can't a flying attacker overcome this?]
                 */
                  if (
 #ifdef STEED
@@ -1084,9 +1125,11 @@ dopois:
                                    Levitation || Flying) {
                    pline("%s tries to reach your %s %s!", Monnam(mtmp),
                          sidestr, body_part(LEG));
+                   dmg = 0;
                  } else if (mtmp->mcan) {
                    pline("%s nuzzles against your %s %s!", Monnam(mtmp),
                          sidestr, body_part(LEG));
+                   dmg = 0;
                  } else {
                    if (uarmf) {
                        if (rn2(2) && (uarmf->otyp == LOW_BOOTS ||
@@ -1099,6 +1142,7 @@ dopois:
                        else {
                            pline("%s scratches your %s boot!", Monnam(mtmp),
                                sidestr);
+                           dmg = 0;
                            break;
                        }
                    } else pline("%s pricks your %s %s!", Monnam(mtmp),
@@ -1120,7 +1164,7 @@ dopois:
                            You_hear("%s hissing!", s_suffix(mon_nam(mtmp)));
                        if(!rn2(10) ||
                            (flags.moonphase == NEW_MOON && !have_lizard())) {
-do_stone:
+ do_stone:
                            if (!Stoned && !Stone_resistance
                                    && !(poly_when_stoned(youmonst.data) &&
                                        polymon(PM_STONE_GOLEM))) {
@@ -1295,6 +1339,11 @@ do_stone:
                hurtarmor(AD_DCAY);
                break;
            case AD_HEAL:
+               /* a cancelled nurse is just an ordinary monster */
+               if (mtmp->mcan) {
+                   hitmsg(mtmp, mattk);
+                   break;
+               }
                if(!uwep
 #ifdef TOURIST
                   && !uarmu
index 70682137efee97e623061251090ee139d8067119..f03e12aff56aa9179376be64a98f414d697989f6 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)uhitm.c    3.4     2002/12/26      */
+/*     SCCS Id: @(#)uhitm.c    3.4     2003/01/02      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1241,6 +1241,12 @@ register struct attack *mattk;
 {
        register struct permonst *pd = mdef->data;
        register int    tmp = d((int)mattk->damn, (int)mattk->damd);
+       int armpro;
+       boolean negated;
+
+       armpro = magic_negation(mdef);
+       /* since hero can't be cancelled, only defender's armor applies */
+       negated = !((rn2(3) >= armpro) || !rn2(50));
 
        if (is_demon(youmonst.data) && !rn2(13) && !uwep
                && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS
@@ -1254,11 +1260,17 @@ register struct attack *mattk;
                    pline("%s %s for a moment.", Monnam(mdef),
                          makeplural(stagger(mdef->data, "stagger")));
                mdef->mstun = 1;
-               /* fall through to next case */
-           case AD_WERE:           /* no effect on monsters */
-           case AD_HEAL:
+               goto physical;
            case AD_LEGS:
+            /* if (u.ucancelled) { */
+            /*    tmp = 0;         */
+            /*    break;           */
+            /* }                   */
+               goto physical;
+           case AD_WERE:           /* no special effect on monsters */
+           case AD_HEAL:           /* likewise */
            case AD_PHYS:
+ physical:
                if(mattk->aatyp == AT_WEAP) {
                    if(uwep) tmp = 0;
                } else if(mattk->aatyp == AT_KICK) {
@@ -1273,13 +1285,17 @@ register struct attack *mattk;
                }
                break;
            case AD_FIRE:
+               if (negated) {
+                   tmp = 0;
+                   break;
+               }
                if (!Blind)
                    pline("%s is %s!", Monnam(mdef),
                          on_fire(mdef->data, mattk));
                if (pd == &mons[PM_STRAW_GOLEM] ||
                    pd == &mons[PM_PAPER_GOLEM]) {
                    if (!Blind)
-                       pline("%s burns completely!", Monnam(mdef));
+                       pline("%s burns completely!", Monnam(mdef));
                    xkilled(mdef,2);
                    tmp = 0;
                    break;
@@ -1298,6 +1314,10 @@ register struct attack *mattk;
                tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
                break;
            case AD_COLD:
+               if (negated) {
+                   tmp = 0;
+                   break;
+               }
                if (!Blind) pline("%s is covered in frost!", Monnam(mdef));
                if (resists_cold(mdef)) {
                    shieldeff(mdef->mx, mdef->my);
@@ -1309,6 +1329,10 @@ register struct attack *mattk;
                tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
                break;
            case AD_ELEC:
+               if (negated) {
+                   tmp = 0;
+                   break;
+               }
                if (!Blind) pline("%s is zapped!", Monnam(mdef));
                tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
                if (resists_elec(mdef)) {
@@ -1365,8 +1389,8 @@ register struct attack *mattk;
                tmp = 0;
                break;
            case AD_TLPT:
-               if(tmp <= 0) tmp = 1;
-               if(tmp < mdef->mhp) {
+               if (tmp <= 0) tmp = 1;
+               if (!negated && tmp < mdef->mhp) {
                    char nambuf[BUFSZ];
                    boolean u_saw_mon = canseemon(mdef);
                    /* record the name before losing sight of monster */
@@ -1403,7 +1427,7 @@ register struct attack *mattk;
                tmp = 0;
                break;
            case AD_DRLI:
-               if (rn2(2) && !resists_drli(mdef)) {
+               if (!negated && !rn2(3) && !resists_drli(mdef)) {
                        int xtmp = d(2,6);
                        pline("%s suddenly seems weaker!", Monnam(mdef));
                        mdef->mhpmax -= xtmp;
@@ -1412,8 +1436,8 @@ register struct attack *mattk;
                                xkilled(mdef,0);
                        } else
                                mdef->m_lev--;
+                       tmp = 0;
                }
-               tmp = 0;
                break;
            case AD_RUST:
                if (pd == &mons[PM_IRON_GOLEM]) {
@@ -1439,7 +1463,7 @@ register struct attack *mattk;
            case AD_DRST:
            case AD_DRDX:
            case AD_DRCO:
-               if (!rn2(8)) {
+               if (!negated && !rn2(8)) {
                    Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk));
                    if (resists_poison(mdef))
                        pline_The("poison doesn't seem to affect %s.",
@@ -1498,7 +1522,7 @@ register struct attack *mattk;
                exercise(A_WIS, TRUE);
                break;
            case AD_STCK:
-               if (!sticks(mdef->data))
+               if (!negated && !sticks(mdef->data))
                    u.ustuck = mdef; /* it's now stuck to you */
                break;
            case AD_WRAP:
@@ -1529,34 +1553,53 @@ register struct attack *mattk;
                } else tmp = 0;
                break;
            case AD_PLYS:
-               if (mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
+               if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
                    if (!Blind) pline("%s is frozen by you!", Monnam(mdef));
                    mdef->mcanmove = 0;
                    mdef->mfrozen = rnd(10);
                }
                break;
            case AD_SLEE:
-               if (!mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) {
+               if (!negated && !mdef->msleeping &&
+                           sleep_monst(mdef, rnd(10), -1)) {
                    if (!Blind)
                        pline("%s is put to sleep by you!", Monnam(mdef));
                    slept_monst(mdef);
                }
                break;
            case AD_SLIM:
-               if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
-                               mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
-                               mdef->data != &mons[PM_SALAMANDER] &&
-                               mdef->data != &mons[PM_GREEN_SLIME]) {
-                   You("turn %s into slime.", mon_nam(mdef));
-                   (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE);
-                   tmp = 0;
-               }
-               break;
+               if (negated) break;     /* physical damage only */
+               if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
+                               mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
+                               mdef->data != &mons[PM_SALAMANDER] &&
+                               mdef->data != &mons[PM_GREEN_SLIME]) {
+                   You("turn %s into slime.", mon_nam(mdef));
+                   (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE);
+                   tmp = 0;
+               }
+               break;
            case AD_ENCH:       /* KMH -- remove enchantment (disenchanter) */
-                       /* There's no msomearmor() function, so just do damage */
-                       break;
+               /* there's no msomearmor() function, so just do damage */
+            /* if (negated) break; */
+               break;
+           case AD_SLOW:
+               if (!negated && mdef->mspeed != MSLOW) {
+                   unsigned int oldspeed = mdef->mspeed;
+
+                   mon_adjust_speed(mdef, -1, (struct obj *)0);
+                   if (mdef->mspeed != oldspeed && canseemon(mdef))
+                       pline("%s slows down.", Monnam(mdef));
+               }
+               break;
+           case AD_CONF:
+               if (!mdef->mconf) {
+                   if (canseemon(mdef))
+                       pline("%s looks confused.", Monnam(mdef));
+                   mdef->mconf = 1;
+               }
+               break;
            default:    tmp = 0;
-                       break;
+               break;
        }
 
        mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */