]> granicus.if.org Git - nethack/commitdiff
munstone fixes (trunk only)
authornethack.rankin <nethack.rankin>
Thu, 13 Apr 2006 07:10:48 +0000 (07:10 +0000)
committernethack.rankin <nethack.rankin>
Thu, 13 Apr 2006 07:10:48 +0000 (07:10 +0000)
     From a bug report, a monster who eats a lizard
corpse in order to cure confusion was treated the same as one who did so
to cure petrification, losing intrinsic speed in the process.  In the same
report by <l>, monsters wouldn't eat lizard corpses to cure being stunned,
and those who ate them for another reason weren't cured of stunning, even
though the hero gets that benefit.  While fixing those, I added some code
to let monsters who are carrying tins of lizard or acidic monster use them
if they're also carrying a tin opener, dagger, or knife.  I don't think
any monsters except for nymphs are willing to pick up tins, so it won't
have much effect.  It now works for nymphs though.

     Examining the code while testing showed that mon_consume_unstone()
has been accessing the potion (acid) or corpse (lizard or acidic monster)
after the item had been used up, so that has been fixed too.  I never saw
any detectable problems due to this, but folks using a debugging malloc
implementation which overwrites freed memory may have not been suffering
collateral acid damage or receiving intended confusion cure, or perhaps
did get either or both of those effects when they shouldn't have.  Since
it only applied to monsters it wouldn't have been easy to observe.

doc/fixes35.0
src/muse.c

index 6262b4e2c9a36dc9f9771127514e670c7ab635a8..1c694c3e084160958f15478fd6cc1861f5b33418 100644 (file)
@@ -136,6 +136,10 @@ preform autopickup and/or report on objects at the spot when a failed #untrap
        attempt causes the hero to move onto a trap's location
 thrown silver weapon hitting silver-hating poly'd hero got double silver damage
 wielded silver weapon hitting silver-hating poly'd hero lacked silver message
+monsters who ate lizard corpses to cure confusion would lose intrinsic speed
+monsters couldn't eat lizard corpses to cure being stunned
+code handling a monster's use of potion or food to cure stoning or confusion
+       was accessing freed memory after the object had been used up
 
 
 Platform- and/or Interface-Specific Fixes
@@ -198,6 +202,7 @@ new effect for reading a scroll of light while confused
 allow digging an adjacent pit with wand of digging while trapped in a pit
 #terrain command for debug mode
 digging can activate or disarm some types of traps
+some monsters can eat tins in addition to corpses to cure some ailments
 
 
 Platform- and/or Interface-Specific New Features
index 9eff9524135433268f3dcd95a78b3b4e4f0119c9..157341465873792dbba70b86306a1b3d972997fc 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)muse.c     3.5     2006/01/04      */
+/*     SCCS Id: @(#)muse.c     3.5     2006/04/11      */
 /*     Copyright (C) 1990 by Ken Arromdee                         */
 /* NetHack may be freely redistributed.  See license for details.  */
 
@@ -28,6 +28,7 @@ STATIC_DCL void FDECL(mbhit,
        (struct monst *,int,int FDECL((*),(MONST_P,OBJ_P)),
        int FDECL((*),(OBJ_P,OBJ_P)),struct obj *));
 STATIC_DCL void FDECL(you_aggravate, (struct monst *));
+STATIC_DCL boolean FDECL(mcould_eat_tin, (struct monst *));
 STATIC_DCL void FDECL(mon_consume_unstone, (struct monst *,struct obj *,
        BOOLEAN_P,BOOLEAN_P));
 
@@ -282,14 +283,25 @@ struct monst *mtmp;
            }
        }
 
-       if (mtmp->mconf) {
-           for(obj = mtmp->minvent; obj; obj = obj->nobj) {
+       if (mtmp->mconf || mtmp->mstun) {
+           struct obj *liztin = 0;
+
+           for (obj = mtmp->minvent; obj; obj = obj->nobj) {
                if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD) {
                    m.defensive = obj;
                    m.has_defense = MUSE_LIZARD_CORPSE;
                    return TRUE;
+               } else if (obj->otyp == TIN && obj->corpsenm == PM_LIZARD) {
+                   liztin = obj;
                }
            }
+           /* confused or stunned monster might not be able to open tin */
+           if (liztin && mcould_eat_tin(mtmp) && rn2(3)) {
+               m.defensive = liztin;
+               /* tin and corpse ultimately end up being handled the same */
+               m.has_defense = MUSE_LIZARD_CORPSE;
+               return TRUE;
+           }
        }
 
        /* It so happens there are two unrelated cases when we might want to
@@ -2107,14 +2119,19 @@ struct monst *mon;
 boolean by_you;
 {
        struct obj *obj;
+       boolean tinok;
 
        if (resists_ston(mon)) return FALSE;
        if (mon->meating || !mon->mcanmove || mon->msleeping) return FALSE;
 
-       for(obj = mon->minvent; obj; obj = obj->nobj) {
-           /* Monsters can also use potions of acid */
-           if ((obj->otyp == POT_ACID) || (obj->otyp == CORPSE &&
-                       (obj->corpsenm == PM_LIZARD || (acidic(&mons[obj->corpsenm]) && obj->corpsenm != PM_GREEN_SLIME)))) {
+       tinok = mcould_eat_tin(mon);
+       for (obj = mon->minvent; obj; obj = obj->nobj) {
+           /* monsters can also use potions of acid */
+           if (obj->otyp == POT_ACID ||
+               ((obj->otyp == CORPSE || (obj->otyp == TIN && tinok)) &&
+                   obj->corpsenm == PM_LIZARD ||
+                   (acidic(&mons[obj->corpsenm]) &&
+                       obj->corpsenm != PM_GREEN_SLIME))) {
                mon_consume_unstone(mon, obj, by_you, TRUE);
                return TRUE;
            }
@@ -2129,46 +2146,54 @@ struct obj *obj;
 boolean by_you;
 boolean stoning;
 {
-    int nutrit = (obj->otyp == CORPSE) ? dog_nutrition(mon, obj) : 0;
-    /* also sets meating */
+    boolean vis = canseemon(mon),
+       tinned = obj->otyp == TIN,
+       food = obj->otyp == CORPSE || tinned,
+       acid = obj->otyp == POT_ACID || (food && acidic(&mons[obj->corpsenm])),
+       lizard = food && obj->corpsenm == PM_LIZARD;
+    int nutrit = food ? dog_nutrition(mon, obj) : 0;  /* also sets meating */
 
     /* give a "<mon> is slowing down" message and also remove
        intrinsic speed (comparable to similar effect on the hero) */
-    mon_adjust_speed(mon, -3, (struct obj *)0);
+    if (stoning) mon_adjust_speed(mon, -3, (struct obj *)0);
 
-    if (canseemon(mon)) {
+    if (vis) {
        long save_quan = obj->quan;
 
        obj->quan = 1L;
-       pline("%s %ss %s.", Monnam(mon),
-                   (obj->otyp == POT_ACID) ? "quaff" : "eat",
-                   distant_name(obj,doname));
+       pline("%s %s %s.", Monnam(mon),
+             (obj->oclass == POTION_CLASS) ? "quaffs" :
+               (obj->otyp == TIN) ? "opens and eats the contents of" :
+                 "eats",
+             distant_name(obj, doname));
        obj->quan = save_quan;
     } else if (!Deaf)
        You_hear("%s.", (obj->otyp == POT_ACID) ? "drinking" : "chewing");
+
     m_useup(mon, obj);
-    if (((obj->otyp == POT_ACID) || acidic(&mons[obj->corpsenm])) &&
-                   !resists_acid(mon)) {
+
+    if (acid && !tinned && !resists_acid(mon)) {
        mon->mhp -= rnd(15);
-       pline("%s has a very bad case of stomach acid.",
-           Monnam(mon));
-    }
-    if (mon->mhp <= 0) {
-       pline("%s dies!", Monnam(mon));
-       if (by_you) xkilled(mon, 0);
-       else mondead(mon);
-       return;
+       if (vis)
+           pline("%s has a very bad case of stomach acid.", Monnam(mon));
+       if (mon->mhp <= 0) {
+           pline("%s dies!", Monnam(mon));
+           if (by_you) xkilled(mon, 0);
+           else mondead(mon);
+           return;
+       }
     }
-    if (stoning && canseemon(mon)) {
+    if (stoning && vis) {
        if (Hallucination)
-    pline("What a pity - %s just ruined a future piece of art!",
-           mon_nam(mon));
+           pline("What a pity - %s just ruined a future piece of art!",
+                 mon_nam(mon));
        else
            pline("%s seems limber!", Monnam(mon));
     }
-    if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD && mon->mconf) {
+    if (lizard && (mon->mconf || mon->mstun)) {
        mon->mconf = 0;
-       if (canseemon(mon))
+       mon->mstun = 0;
+       if (vis && !is_bat(mon->data) && mon->data != &mons[PM_STALKER])
            pline("%s seems steadier now.", Monnam(mon));
     }
     if (mon->mtame && !mon->isminion && nutrit > 0) {
@@ -2181,4 +2206,31 @@ boolean stoning;
     mon->mlstmv = monstermoves; /* it takes a turn */
 }
 
+STATIC_OVL boolean
+mcould_eat_tin(mon)
+struct monst *mon;
+{
+       struct obj *obj, *mwep;
+
+       /* monkeys who manage to steal tins can't open and eat them
+          even if they happen to also have the appropriate tool */
+       if (is_animal(mon->data)) return FALSE;
+
+       mwep = MON_WEP(mon);
+       /* this is different from the player; tin opener or dagger doesn't
+          have to be wielded, and knife can be used instead of dagger
+          (even so, non-nymphs don't pick up tins, so only nymphs might
+          end up being able to benefit from them) */
+       for (obj = mon->minvent; obj; obj = obj->nobj) {
+           /* if stuck with a cursed weapon, don't check rest of inventory */
+           if (mwep && mwep->cursed && obj != mwep) continue;
+
+           if (obj->otyp == TIN_OPENER ||
+               (obj->oclass == WEAPON_CLASS &&
+                   (objects[obj->otyp].oc_skill == P_DAGGER ||
+                    objects[obj->otyp].oc_skill == P_KNIFE))) return TRUE;
+       }
+       return FALSE;
+}
+
 /*muse.c*/