]> granicus.if.org Git - nethack/commitdiff
fix #332 - strangulation affects headless monsters (trunk only)
authornethack.rankin <nethack.rankin>
Fri, 18 May 2007 02:10:39 +0000 (02:10 +0000)
committernethack.rankin <nethack.rankin>
Fri, 18 May 2007 02:10:39 +0000 (02:10 +0000)
     From a bug report:  amulet of strangulation
continues to kill hero if he polymorphs into a creature which doesn't
need to breathe or doesn't have a head or even a circulatory system.
Currently, the messages are different when the hero doesn't need to
breathe, but that doesn't seem good enough.  This makes strangulation
stop when you polymorph into something which shouldn't be vulnerable and
restart if you poly into something vulnerable while still wearing the
bad amulet.

     can_be_strangled() is doing more checks that necessary, in case the
strangulation property ever gets conferred by something other than an
amulet.  Its criteria for protection from strangling might need tweaking.

doc/fixes35.0
include/extern.h
src/do_wear.c
src/mondata.c
src/polyself.c
src/timeout.c

index d7ad633298977423f9c1d34f377dd8add6038419..2e49b4fbae2c2eddff225913972e3bbaa1828f24 100644 (file)
@@ -229,6 +229,7 @@ eliminate case-sensitivity when converting words from singular to plural and
 breath attack directed at self by poly'd hero always hits
 override non-silver vs shades for artifacts which deal extra damage to undead
 assorted mirror fixes--mainly visibility issues
+some monsters can't be strangled; self-polymorph can stop/restart strangulation
 
 
 Platform- and/or Interface-Specific Fixes
index 1b75c11a157fecc8e14a47ae151191e5c4e1a08e..d15118c6ddca818fd8dae4661606cd194be4ae97 100644 (file)
@@ -1329,6 +1329,7 @@ E boolean FDECL(hates_silver, (struct permonst *));
 E boolean FDECL(mon_hates_silver, (struct monst *));
 E boolean FDECL(passes_bars, (struct permonst *));
 E boolean FDECL(can_blow, (struct monst *));
+E boolean FDECL(can_be_strangled, (struct monst *));
 E boolean FDECL(can_track, (struct permonst *));
 E boolean FDECL(breakarm, (struct permonst *));
 E boolean FDECL(sliparm, (struct permonst *));
index 9044f793046444f075e8f0bb42704c80e9d1387f..8ce78939be1fc1371bc5bccadf1025f9081bb8ae 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)do_wear.c  3.5     2007/03/19      */
+/*     SCCS Id: @(#)do_wear.c  3.5     2007/05/16      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -626,9 +626,11 @@ Amulet_on()
                break;
            }
        case AMULET_OF_STRANGULATION:
-               makeknown(AMULET_OF_STRANGULATION);
-               pline("It constricts your throat!");
-               Strangled = 6;
+               if (can_be_strangled(&youmonst)) {
+                   makeknown(AMULET_OF_STRANGULATION);
+                   pline("It constricts your throat!");
+                   Strangled = 6L;
+               }
                break;
        case AMULET_OF_RESTFUL_SLEEP:
                HSleeping = rnd(100);
@@ -671,8 +673,11 @@ Amulet_off()
                break;
        case AMULET_OF_STRANGULATION:
                if (Strangled) {
+                   if (Breathless)
+                       Your("%s is no longer constricted!", body_part(NECK));
+                   else
                        You("can breathe more easily!");
-                       Strangled = 0;
+                   Strangled = 0L;
                }
                break;
        case AMULET_OF_RESTFUL_SLEEP:
index f3e319fea0f57ac4808030296083ea0e6a69d538..cd8010b5d795d9c959774f9de288c04050198836 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)mondata.c  3.5     2007/03/02      */
+/*     SCCS Id: @(#)mondata.c  3.5     2007/05/16      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -299,6 +299,37 @@ register struct monst *mtmp;
        return TRUE;
 }
 
+boolean
+can_be_strangled(mon)  /* TRUE if mon is vulnerable to strangulation */
+struct monst *mon;
+{
+    struct obj *mamul;
+    boolean nonbreathing, nobrainer;
+
+    /* For amulet of strangulation support:  here we're considering
+       strangulation to be loss of blood flow to the brain due to
+       constriction of the arteries in the neck, so all headless
+       creatures are immune (no neck) as are mindless creatures
+       who don't need to breathe (brain, if any, doesn't care).
+       Mindless creatures who do need to breath are vulnerable, as
+       are non-breathing creatures which have higher brain function. */
+    if (!has_head(mon->data)) return FALSE;
+    if (mon == &youmonst) {
+       /* hero can't be mindless but poly'ing into mindless form can
+          confer strangulation protection */
+       nobrainer = mindless(youmonst.data);
+       nonbreathing = Breathless;
+    } else {
+       nobrainer = mindless(mon->data);
+       /* monsters don't wear amulets of magical breathing,
+          so second part doesn't achieve anything useful... */
+       nonbreathing = (breathless(mon->data) ||
+                       ((mamul = which_armor(mon, W_AMUL)) != 0 &&
+                        (mamul->otyp == AMULET_OF_MAGICAL_BREATHING)));
+    }
+    return (boolean)(!nobrainer || !nonbreathing);
+}
+
 boolean
 can_track(ptr)         /* returns TRUE if monster can track well */
        register struct permonst *ptr;
index fe79890239cfbb73690c16b5a452a20f6163176e..20d1ff1478ad3db130ffdfdef169c65d9c35697b 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "hack.h"
 
+STATIC_DCL void FDECL(check_strangling, (BOOLEAN_P));
 STATIC_DCL void FDECL(polyman, (const char *,const char *));
 STATIC_DCL void NDECL(break_armor);
 STATIC_DCL void FDECL(drop_weapon,(int));
@@ -46,6 +47,30 @@ set_uasmon()
 #endif
 }
 
+/* for changing into form that's immune to strangulation */
+STATIC_OVL void
+check_strangling(on)
+boolean on;
+{
+    if (on) {  /* on -- maybe resume strangling */
+       /* when Strangled is already set, polymorphing from one
+          vulnerable form into another causes the counter to be reset */
+       if (uamul && uamul->otyp == AMULET_OF_STRANGULATION &&
+               can_be_strangled(&youmonst)) {
+           Your("%s %s your %s!", simpleonames(uamul),
+               Strangled ? "still constricts" : "begins constricting",
+               body_part(NECK)); /* "throat" */
+           Strangled = 6L;
+           makeknown(AMULET_OF_STRANGULATION);
+       }
+    } else {   /* off -- maybe block strangling */
+       if (Strangled && !can_be_strangled(&youmonst)) {
+           Strangled = 0L;
+           You("are no longer being strangled.");
+       }
+    }
+}
+
 /* make a (new) human out of the player */
 STATIC_OVL void
 polyman(fmt, arg)
@@ -109,6 +134,7 @@ const char *fmt, *arg;
            Blinded = 1L;
            make_blinded(0L, TRUE);     /* remove blindness */
        }
+       check_strangling(TRUE);
 
        if(!Levitation && !u.ustuck &&
           (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy)))
@@ -491,6 +517,7 @@ int mntmp;
                make_slimed(0L, (char*) 0);
            }
        }
+       check_strangling(FALSE); /* maybe stop strangling */
        if (nohands(youmonst.data)) Glib = 0;
 
        /*
@@ -631,6 +658,7 @@ int mntmp;
            You("orient yourself on the web.");
            u.utrap = 0;
        }
+       check_strangling(TRUE); /* maybe start strangling */
        (void) polysense(youmonst.data);
 
        context.botl = 1;
index a3898ce4b97678368f997e7479d31c711f832bbc..b0f7793bcf511dbd3e669e7a2653183d04770b7c 100644 (file)
@@ -354,6 +354,12 @@ nh_timeout()
                        Strcpy(killer.name,
                               (u.uburied) ? "suffocation" : "strangulation");
                        done(DIED);
+                       /* must be declining to die in explore|wizard mode;
+                          treat like being cured of strangulation by prayer */
+                       if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
+                           Your("amulet vanishes!");
+                           useup(uamul);
+                       }
                        break;
                case FUMBLING:
                        /* call this only when a move took place.  */